diff --git "a/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/API\345\217\202\350\200\203.md" "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/API\345\217\202\350\200\203.md" new file mode 100644 index 00000000..d517e12b --- /dev/null +++ "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/API\345\217\202\350\200\203.md" @@ -0,0 +1,653 @@ +# API参考 + + +**本文档中引用的文件** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [UserController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java) +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java) +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [OpenApiController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/OpenApiController.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) +- [Status.java](file://datavines-core/src/main/java/io/datavines/core/enums/Status.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [UserLogin.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserLogin.java) +- [WorkSpaceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceCreate.java) +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) +- [SubmitJob.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/SubmitJob.java) + + +## 目录 +1. [简介](#简介) +2. [API基础信息](#api基础信息) +3. [认证与授权](#认证与授权) +4. [API版本策略](#api版本策略) +5. [错误处理](#错误处理) +6. [核心API端点](#核心api端点) +7. [API使用示例](#api使用示例) +8. [客户端开发指导](#客户端开发指导) + +## 简介 +DataVines提供了一套完整的RESTful API接口,用于管理和操作数据质量检查系统。本API参考文档全面记录了所有可用的API端点,包括用户管理、工作空间管理、数据源管理、作业管理、执行控制等功能。API设计遵循REST原则,使用JSON格式进行数据交换,并通过标准HTTP状态码和自定义错误码提供清晰的响应信息。 + +**API特点:** +- 基于Spring Boot和Swagger构建 +- 使用JWT进行身份验证 +- 支持OpenAPI 2.0规范 +- 提供详细的错误信息和状态码 +- 支持外部系统集成 + +## API基础信息 + +### 基础URL +所有API端点的基础URL为: +``` +http://:/api/v1 +``` + +其中``是DataVines服务器地址,``是服务端口(默认为56001)。 + +### HTTP方法 +API使用标准的HTTP方法: +- `GET`:获取资源 +- `POST`:创建资源或执行操作 +- `PUT`:更新资源 +- `DELETE`:删除资源 + +### 内容类型 +所有请求和响应的内容类型均为`application/json`。 + +### 请求头 +| 头部名称 | 描述 | 是否必需 | +|---------|------|---------| +| Authorization | Bearer令牌,用于身份验证 | 是(除登录等公开接口外) | +| Content-Type | 请求内容类型,应设置为application/json | 是 | + +### 响应结构 +所有API响应都遵循统一的响应格式,由`ResultMap`类定义: + +```json +{ + "code": 200, + "msg": "Success", + "data": {}, + "token": "optional_token" +} +``` + +**字段说明:** +- `code`:状态码,200表示成功,其他值表示错误 +- `msg`:消息描述,成功时为"Success",错误时为具体的错误信息 +- `data`:实际返回的数据,如果无数据则为"{}" +- `token`:可选的JWT令牌,仅在登录等需要认证的接口返回 + +**Section sources** +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) + +## 认证与授权 + +### 认证机制 +DataVines使用基于JWT(JSON Web Token)的认证机制。用户通过登录接口获取令牌,后续请求需要在`Authorization`头部中携带该令牌。 + +#### 登录流程 +1. 用户通过`/api/v1/login`端点提交用户名和密码 +2. 服务器验证凭据,生成JWT令牌 +3. 令牌通过响应返回给客户端 +4. 客户端在后续请求的`Authorization`头部中携带`Bearer ` + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Server as 服务器 +Client->>Server : POST /api/v1/login +Server->>Server : 验证用户名和密码 +Server->>Server : 生成JWT令牌 +Server-->>Client : 返回包含令牌的响应 +Client->>Server : 后续请求携带Authorization头部 +Server->>Server : 验证令牌有效性 +Server-->>Client : 返回请求的资源 +``` + +**Diagram sources** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +### 权限控制 +系统通过拦截器实现权限控制,主要机制包括: + +1. **公开接口**:使用`@AuthIgnore`注解标记,无需认证即可访问 +2. **认证接口**:需要有效的JWT令牌 +3. **令牌验证**:拦截器验证令牌的有效性和用户状态 + +```mermaid +flowchart TD +Start([请求到达]) --> CheckAuth["检查@AuthIgnore注解"] +CheckAuth --> |是| Allow["允许访问"] +CheckAuth --> |否| CheckToken["检查Authorization头部"] +CheckToken --> |无令牌| ReturnError["返回401错误"] +CheckToken --> |有令牌| ValidateToken["验证令牌有效性"] +ValidateToken --> |无效| ReturnError +ValidateToken --> |有效| GetUser["获取用户信息"] +GetUser --> CheckUser["检查用户是否存在"] +CheckUser --> |不存在| ReturnError +CheckUser --> |存在| Allow +ReturnError --> End([返回错误响应]) +Allow --> End +``` + +**Diagram sources** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +### 令牌管理 +- **令牌格式**:`Bearer `,符合RFC 6750标准 +- **令牌有效期**:系统自动管理令牌的刷新和过期 +- **令牌刷新**:通过`@RefreshToken`注解实现自动刷新机制 + +**Section sources** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) + +## API版本策略 + +### 版本控制 +API采用URL路径进行版本控制,当前版本为v1: + +``` +/api/v1/ +``` + +### 向后兼容性 +DataVines承诺保持向后兼容性,具体策略如下: + +1. **功能添加**:新增功能不会影响现有API +2. **字段添加**:响应中可能添加新字段,但不会删除或修改现有字段 +3. **弃用通知**:计划弃用的API会提前通知,并保持一段时间的兼容性 +4. **版本升级**:重大变更将通过版本号升级(如v2)来标识 + +### 版本迁移 +当需要升级到新版本时: +1. 检查API文档中的变更日志 +2. 测试新版本的兼容性 +3. 逐步迁移客户端代码 +4. 监控迁移过程中的错误 + +**Section sources** +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) + +## 错误处理 + +### 错误响应格式 +当请求失败时,API返回标准化的错误响应: + +```json +{ + "code": 400, + "msg": "Bad Request", + "data": "{}" +} +``` + +### 常见错误码 +| 状态码 | 错误码 | 描述 | 解决方案 | +|-------|-------|------|---------| +| 200 | 200 | 成功 | 无需处理 | +| 400 | 10010001 | 请求错误 | 检查请求参数和格式 | +| 401 | 10010002 | 无效的令牌 | 重新登录获取新令牌 | +| 401 | 10010003 | 令牌为空 | 在请求头中添加Authorization | +| 401 | 10010004 | 请登录 | 执行登录操作 | +| 400 | 10020001 | 用户名已被注册 | 使用其他用户名 | +| 400 | 11010001 | 工作空间已存在 | 使用其他名称 | +| 400 | 12010001 | 数据源已存在 | 使用其他名称 | +| 400 | 14010003 | 作业不存在 | 检查作业ID | + +### 错误处理机制 +系统通过全局异常处理器`DataVinesExceptionHandler`统一处理各种异常: + +```mermaid +flowchart TD +Start([异常抛出]) --> CheckType["检查异常类型"] +CheckType --> |DataVinesServerException| HandleServer["处理业务异常"] +CheckType --> |ConstraintViolationException| HandleValidation["处理参数验证异常"] +CheckType --> |MethodArgumentNotValidException| HandleValidation +CheckType --> |其他异常| HandleCommon["处理通用异常"] +HandleServer --> BuildResponse["构建错误响应"] +HandleValidation --> BuildResponse +HandleCommon --> BuildResponse +BuildResponse --> LogError["记录错误日志"] +LogError --> ReturnResponse["返回标准化错误响应"] +``` + +**Diagram sources** +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) +- [Status.java](file://datavines-core/src/main/java/io/datavines/core/enums/Status.java) + +### 参数验证 +API使用JSR-303 Bean Validation进行参数验证,常见验证注解包括: +- `@NotBlank`:字符串不能为空 +- `@NotNull`:对象不能为空 +- `@Pattern`:字符串需匹配正则表达式 +- `@Valid`:验证嵌套对象 + +**Section sources** +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) +- [Status.java](file://datavines-core/src/main/java/io/datavines/core/enums/Status.java) + +## 核心API端点 + +### 用户管理API +管理用户账户和认证。 + +#### 登录 +- **HTTP方法**: POST +- **URL**: `/api/v1/login` +- **描述**: 用户登录系统 +- **请求体**: +```json +{ + "username": "string", + "password": "string" +} +``` +- **响应**: +```json +{ + "code": 200, + "msg": "Success", + "data": {}, + "token": "jwt_token" +} +``` + +#### 注册 +- **HTTP方法**: POST +- **URL**: `/api/v1/register` +- **描述**: 新用户注册 +- **请求体**: +```json +{ + "username": "string", + "password": "string", + "email": "string", + "verificationCode": "string", + "verificationCodeJwt": "string" +} +``` + +#### 重置密码 +- **HTTP方法**: POST +- **URL**: `/api/v1/user/resetPassword` +- **描述**: 重置用户密码 +- **请求体**: +```json +{ + "username": "string", + "oldPassword": "string", + "newPassword": "string", + "confirmPassword": "string" +} +``` + +**Section sources** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [UserController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java) +- [UserLogin.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserLogin.java) + +### 工作空间管理API +管理用户的工作空间。 + +#### 创建工作空间 +- **HTTP方法**: POST +- **URL**: `/api/v1/workspace` +- **描述**: 创建新的工作空间 +- **请求体**: +```json +{ + "name": "string", + "description": "string" +} +``` +- **响应**: 工作空间ID + +#### 获取工作空间列表 +- **HTTP方法**: GET +- **URL**: `/api/v1/workspace/list` +- **描述**: 获取当前用户的所有工作空间 +- **响应**: 工作空间对象数组 + +#### 邀请用户 +- **HTTP方法**: POST +- **URL**: `/api/v1/workspace/inviteUser` +- **描述**: 邀请用户加入工作空间 +- **请求体**: +```json +{ + "workspaceId": 0, + "username": "string" +} +``` + +**Section sources** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java) + +### 数据源管理API +管理数据源连接和元数据。 + +#### 测试数据源连接 +- **HTTP方法**: POST +- **URL**: `/api/v1/datasource/test` +- **描述**: 测试数据源连接是否有效 +- **请求体**: +```json +{ + "type": "string", + "parameters": {} +} +``` + +#### 创建数据源 +- **HTTP方法**: POST +- **URL**: `/api/v1/datasource` +- **描述**: 创建新的数据源连接 +- **请求体**: +```json +{ + "name": "string", + "type": "string", + "workSpaceId": 0, + "parameters": {} +} +``` + +#### 获取数据库列表 +- **HTTP方法**: GET +- **URL**: `/api/v1/datasource/{id}/databases` +- **描述**: 获取指定数据源的数据库列表 +- **路径参数**: `id` - 数据源ID + +#### 执行SQL脚本 +- **HTTP方法**: POST +- **URL**: `/api/v1/datasource/execute` +- **描述**: 在指定数据源上执行SQL脚本 +- **请求体**: +```json +{ + "dataSourceId": 0, + "database": "string", + "script": "string" +} +``` + +**Section sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) + +### 作业管理API +管理数据质量检查作业。 + +#### 创建作业 +- **HTTP方法**: POST +- **URL**: `/api/v1/job` +- **描述**: 创建新的数据质量检查作业 +- **请求体**: +```json +{ + "name": "string", + "type": 0, + "dataSourceId": 0, + "metricParameters": [] +} +``` + +#### 获取作业列表 +- **HTTP方法**: GET +- **URL**: `/api/v1/job/page` +- **描述**: 分页获取作业列表 +- **查询参数**: + - `searchVal`: 搜索关键字 + - `datasourceId`: 数据源ID + - `pageNumber`: 页码 + - `pageSize`: 每页数量 + +#### 执行作业 +- **HTTP方法**: POST +- **URL**: `/api/v1/job/execute/{id}` +- **描述**: 执行指定ID的作业 +- **路径参数**: `id` - 作业ID + +**Section sources** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) + +### 作业执行API +管理作业的执行和监控。 + +#### 提交数据质量作业 +- **HTTP方法**: POST +- **URL**: `/api/v1/job/execution/submit/data-quality` +- **描述**: 提交外部数据质量检查作业 +- **请求体**: `SubmitJob`对象 + +#### 获取执行状态 +- **HTTP方法**: GET +- **URL**: `/api/v1/job/execution/status/{executionId}` +- **描述**: 获取指定执行实例的状态 +- **路径参数**: `executionId` - 执行ID + +#### 终止执行 +- **HTTP方法**: DELETE +- **URL**: `/api/v1/job/execution/kill/{executionId}` +- **描述**: 终止正在运行的作业执行 +- **路径参数**: `executionId` - 执行ID + +#### 获取执行结果 +- **HTTP方法**: GET +- **URL**: `/api/v1/job/execution/list/result/{executionId}` +- **描述**: 获取作业执行的详细结果 +- **路径参数**: `executionId` - 执行ID + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) + +### OpenAPI端点 +为外部系统集成提供的简化API。 + +#### 执行作业(OpenAPI) +- **HTTP方法**: POST +- **URL**: `/api/v1/openapi/job/execute/{id}` +- **描述**: 通过OpenAPI执行作业,需要`CheckTokenExist`验证 +- **路径参数**: `id` - 作业ID + +#### 终止执行(OpenAPI) +- **HTTP方法**: POST +- **URL**: `/api/v1/openapi/job/execution/kill/{executionId}` +- **描述**: 通过OpenAPI终止执行 +- **路径参数**: `executionId` - 执行ID + +**Section sources** +- [OpenApiController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/OpenApiController.java) + +## API使用示例 + +### Python客户端示例 +```python +import requests +import json + +class DataVinesClient: + def __init__(self, base_url, username, password): + self.base_url = base_url + self.username = username + self.password = password + self.token = None + self.session = requests.Session() + + def login(self): + """登录并获取令牌""" + url = f"{self.base_url}/api/v1/login" + payload = { + "username": self.username, + "password": self.password + } + + response = self.session.post(url, json=payload) + data = response.json() + + if data["code"] == 200: + self.token = data["token"] + # 设置默认头部 + self.session.headers.update({ + "Authorization": f"Bearer {self.token}", + "Content-Type": "application/json" + }) + return True + else: + raise Exception(f"登录失败: {data['msg']}") + + def create_workspace(self, name, description=""): + """创建工作空间""" + url = f"{self.base_url}/api/v1/workspace" + payload = { + "name": name, + "description": description + } + + response = self.session.post(url, json=payload) + return response.json() + + def test_datasource_connection(self, datasource_params): + """测试数据源连接""" + url = f"{self.base_url}/api/v1/datasource/test" + response = self.session.post(url, json=datasource_params) + return response.json() + +# 使用示例 +client = DataVinesClient("http://localhost:56001", "admin", "admin") +client.login() + +# 创建工作空间 +workspace = client.create_workspace("测试工作空间", "用于API测试") +print(workspace) + +# 测试MySQL连接 +mysql_test = client.test_datasource_connection({ + "type": "mysql", + "parameters": { + "host": "localhost", + "port": 3306, + "username": "test", + "password": "test" + } +}) +print(mysql_test) +``` + +### cURL示例 +```bash +# 1. 登录获取令牌 +TOKEN=$(curl -X POST "http://localhost:56001/api/v1/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"admin"}' \ + | grep -o '"token":"[^"]*"' | cut -d'"' -f4) + +echo "Token: $TOKEN" + +# 2. 使用令牌创建工作空间 +curl -X POST "http://localhost:56001/api/v1/workspace" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "API测试空间", + "description": "通过API创建的工作空间" + }' + +# 3. 获取工作空间列表 +curl -X GET "http://localhost:56001/api/v1/workspace/list" \ + -H "Authorization: Bearer $TOKEN" +``` + +### Java客户端示例 +```java +import org.springframework.web.client.RestTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +public class DataVinesApiClient { + private final String baseUrl; + private final RestTemplate restTemplate; + private String token; + + public DataVinesApiClient(String baseUrl) { + this.baseUrl = baseUrl; + this.restTemplate = new RestTemplate(); + } + + public boolean login(String username, String password) { + String url = baseUrl + "/api/v1/login"; + LoginRequest request = new LoginRequest(username, password); + + try { + ResultMap response = restTemplate.postForObject(url, request, ResultMap.class); + if (response != null && response.getCode() == 200) { + this.token = (String) response.get("token"); + return true; + } + } catch (Exception e) { + System.err.println("登录失败: " + e.getMessage()); + } + return false; + } + + public ResultMap createWorkspace(String name, String description) { + String url = baseUrl + "/api/v1/workspace"; + WorkSpaceCreate request = new WorkSpaceCreate(); + request.setName(name); + request.setDescription(description); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("Authorization", "Bearer " + token); + + HttpEntity entity = new HttpEntity<>(request, headers); + return restTemplate.postForObject(url, entity, ResultMap.class); + } +} +``` + +**Section sources** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java) + +## 客户端开发指导 + +### 最佳实践 +1. **错误处理**:始终检查响应的`code`字段,不要假设请求总是成功 +2. **令牌管理**:妥善存储和管理JWT令牌,避免泄露 +3. **重试机制**:对于临时性错误(如网络问题),实现指数退避重试 +4. **连接池**:使用HTTP连接池提高性能 +5. **超时设置**:设置合理的请求超时时间 + +### 性能优化 +- **批量操作**:尽量使用批量API减少请求次数 +- **缓存**:对不经常变化的数据进行本地缓存 +- **并发请求**:对于独立的操作,使用并发请求提高效率 +- **压缩**:启用GZIP压缩减少网络传输 + +### 安全建议 +1. **HTTPS**:生产环境必须使用HTTPS加密通信 +2. **令牌存储**:在安全的存储中保存令牌,避免明文存储 +3. **最小权限**:使用具有最小必要权限的账户 +4. **审计日志**:记录重要的API调用以供审计 + +### 调试技巧 +1. **启用详细日志**:在开发环境中启用详细的HTTP日志 +2. **使用Swagger UI**:通过Swagger UI直接测试API +3. **监控响应时间**:跟踪API调用的响应时间 +4. **验证请求体**:确保请求体格式正确,特别是JSON结构 + +**Section sources** +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241API.md" "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241API.md" new file mode 100644 index 00000000..87081a3e --- /dev/null +++ "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241API.md" @@ -0,0 +1,277 @@ +# 任务API + + +**本文档中引用的文件** +- [CommonTaskController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskController.java) +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java) +- [CommonTaskService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskService.java) +- [CommonTaskScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskScheduleService.java) +- [CommonTaskScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/task/CommonTaskScheduleCreateOrUpdate.java) +- [CommonTask.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/CommonTask.java) +- [CommonTaskSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/CommonTaskSchedule.java) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档全面记录了与质量检查任务管理相关的所有RESTful接口。详细描述了创建、更新、删除、启动和查询质量检查任务的API端点,包括HTTP方法、URL路径、请求参数和请求体结构。文档化了任务配置的完整JSON结构,包括数据源选择、检查规则配置、预期值设置、通知策略等。提供了不同类型任务(单表检查、跨表检查等)的配置示例。解释了任务克隆、批量操作等高级功能的API使用方法。包含了任务状态转换的详细说明和相应的API调用方式。 + +## 项目结构 +本项目采用模块化设计,主要分为以下几个核心模块: +- **datavines-common**: 提供通用配置、数据源连接、异常处理等基础功能 +- **datavines-server**: 核心服务模块,包含API控制器、业务逻辑和服务层 +- **datavines-metric**: 质量检查指标管理模块 +- **datavines-notification**: 通知系统模块 +- **datavines-connector**: 数据源连接器模块 +- **datavines-engine**: 执行引擎模块 + +任务管理相关的API主要位于`datavines-server`模块中,通过Spring Boot框架提供RESTful服务。 + +```mermaid +graph TD +subgraph "前端" +UI[用户界面] +end +subgraph "后端服务" +API[API服务器] +Service[业务服务层] +Repository[数据访问层] +end +subgraph "数据存储" +DB[(数据库)] +end +UI --> API +API --> Service +Service --> Repository +Repository --> DB +``` + +**图表来源** +- [CommonTaskController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskController.java#L29-L31) +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java#L34-L36) + +**章节来源** +- [CommonTaskController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskController.java#L1-L47) +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java#L1-L61) + +## 核心组件 +质量检查任务管理的核心组件包括任务控制器(CommonTaskController)、任务调度控制器(CommonTaskScheduleController)、任务服务(CommonTaskService)和任务调度服务(CommonTaskScheduleService)。这些组件共同实现了任务的创建、更新、删除、查询和调度功能。 + +任务管理采用分层架构设计,控制器层负责接收HTTP请求,服务层处理业务逻辑,数据访问层负责与数据库交互。任务状态管理通过数据库中的状态字段实现,支持任务的生命周期管理。 + +**章节来源** +- [CommonTaskService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskService.java#L28-L49) +- [CommonTaskScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskScheduleService.java#L28-L42) + +## 架构概述 +质量检查任务管理系统的架构采用典型的三层设计模式:表现层、业务逻辑层和数据访问层。表现层由Spring MVC控制器组成,负责处理RESTful API请求;业务逻辑层包含服务类,实现核心业务规则;数据访问层使用MyBatis Plus框架,提供对数据库的CRUD操作。 + +系统通过CommonTask和CommonTaskSchedule两个主要实体类来管理任务及其调度配置。任务与数据源关联,支持多种任务类型,包括元数据抓取和数据质量报告。 + +```mermaid +classDiagram +class CommonTask { ++Long id ++CommonTaskType taskType ++FetchType type ++Long dataSourceId ++String databaseName ++String tableName ++String parameter ++int status ++String executeHost ++LocalDateTime submitTime ++LocalDateTime scheduleTime ++LocalDateTime startTime ++LocalDateTime endTime ++LocalDateTime createTime ++LocalDateTime updateTime +} +class CommonTaskSchedule { ++Long id ++Long dataSourceId ++CommonTaskType taskType ++String type ++String param ++String cronExpression ++boolean status ++LocalDateTime startTime ++LocalDateTime endTime ++Long createBy ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +class CommonTaskService { ++IPage~CatalogMetaDataFetchTaskVO~ getFetchTaskPage(Long, String, Integer, Integer) ++long refreshCatalog(CatalogRefresh) ++int update(CommonTask) ++CommonTask getById(long) ++Long killCatalogTask(Long) ++CommonTask[] listNeedFailover(String) ++CommonTask[] listTaskNotInServerList(String[]) ++String getTaskExecuteHost(Long) ++boolean deleteByDataSourceId(long) ++LocalDateTime getRefreshTime(long, String, String) +} +class CommonTaskScheduleService { ++CommonTaskSchedule createOrUpdate(CommonTaskScheduleCreateOrUpdate) ++boolean deleteById(long) ++boolean deleteByDataSourceId(long) ++CommonTaskSchedule getById(long) ++CommonTaskSchedule getByDataSourceId(Long, String) ++String[] getCron(MapParam) +} +CommonTaskController --> CommonTaskService : "依赖" +CommonTaskScheduleController --> CommonTaskScheduleService : "依赖" +CommonTaskService --> CommonTask : "管理" +CommonTaskScheduleService --> CommonTaskSchedule : "管理" +``` + +**图表来源** +- [CommonTask.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/CommonTask.java#L31-L88) +- [CommonTaskSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/CommonTaskSchedule.java#L30-L79) + +## 详细组件分析 +### 任务控制器分析 +任务控制器(CommonTaskController)负责处理与任务相关的HTTP请求,提供分页查询任务列表的功能。该控制器通过RESTful API暴露服务,使用Spring MVC注解定义路由和请求处理方法。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "CommonTaskController" +participant Service as "CommonTaskService" +participant Repository as "数据访问层" +Client->>Controller : GET /api/v1/common-task/page +Controller->>Service : getFetchTaskPage(datasourceId, taskType, pageNumber, pageSize) +Service->>Repository : 查询任务分页数据 +Repository-->>Service : 返回分页结果 +Service-->>Controller : 返回任务列表 +Controller-->>Client : 返回JSON响应 +``` + +**图表来源** +- [CommonTaskController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskController.java#L39-L46) +- [CommonTaskService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskService.java#L48-L49) + +### 任务调度控制器分析 +任务调度控制器(CommonTaskScheduleController)负责处理任务调度相关的创建、更新、查询操作。该控制器提供了创建或更新任务调度、根据数据源ID获取任务调度、获取cron表达式等核心功能。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "CommonTaskScheduleController" +participant Service as "CommonTaskScheduleService" +participant Repository as "数据访问层" +Client->>Controller : POST /api/v1/common-task/schedule/createOrUpdate +Controller->>Service : createOrUpdate(taskScheduleCreateOrUpdate) +Service->>Repository : 保存或更新任务调度 +Repository-->>Service : 返回保存结果 +Service-->>Controller : 返回任务调度信息 +Controller-->>Client : 返回JSON响应 +``` + +**图表来源** +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java#L44-L48) +- [CommonTaskScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskScheduleService.java#L30-L31) + +### 任务调度配置分析 +任务调度配置(CommonTaskScheduleCreateOrUpdate)是创建和更新任务调度的核心数据传输对象。该类定义了任务调度所需的所有必要字段,包括任务ID、任务类型、数据源ID、调度类型、参数、开始时间和结束时间。 + +```mermaid +classDiagram +class CommonTaskScheduleCreateOrUpdate { ++Long id ++CommonTaskType taskType ++Long dataSourceId ++String type ++MapParam param ++LocalDateTime startTime ++LocalDateTime endTime +} +class CommonTaskType { ++CATALOG_METADATA_FETCH(0, "catalog_metadata_fetch", "元数据抓取") ++DATA_QUALITY_REPORT(1, "data_quality_report", "数据质量报告") +} +class MapParam { ++String cycle ++String timeZone +} +CommonTaskScheduleCreateOrUpdate --> CommonTaskType : "引用" +CommonTaskScheduleCreateOrUpdate --> MapParam : "包含" +``` + +**图表来源** +- [CommonTaskScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/task/CommonTaskScheduleCreateOrUpdate.java#L28-L51) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java#L24-L74) + +**章节来源** +- [CommonTaskScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/task/CommonTaskScheduleCreateOrUpdate.java#L1-L51) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java#L1-L74) + +## 依赖分析 +质量检查任务管理系统依赖于多个核心模块和外部库。系统内部依赖关系清晰,各模块职责分明。主要依赖包括: + +```mermaid +graph TD +CommonTaskController --> CommonTaskService +CommonTaskScheduleController --> CommonTaskScheduleService +CommonTaskService --> CommonTask +CommonTaskScheduleService --> CommonTaskSchedule +CommonTaskScheduleService --> CommonTaskType +CommonTaskController --> DataVinesConstants +CommonTaskScheduleController --> DataVinesConstants +CommonTaskService --> CatalogRefresh +CommonTaskScheduleService --> MapParam +style CommonTaskController fill:#f9f,stroke:#333 +style CommonTaskScheduleController fill:#f9f,stroke:#333 +``` + +**图表来源** +- [CommonTaskController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskController.java#L36-L37) +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java#L41-L42) + +**章节来源** +- [CommonTaskService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskService.java#L19-L27) +- [CommonTaskScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskScheduleService.java#L21-L27) + +## 性能考虑 +在设计和实现质量检查任务管理系统时,考虑了以下性能优化策略: +- 使用MyBatis Plus框架提高数据库操作效率 +- 通过分页查询避免一次性加载大量数据 +- 合理设计数据库索引,特别是在常用查询字段上 +- 使用缓存机制减少重复计算 +- 异步处理耗时操作,提高系统响应速度 + +对于大规模任务管理,建议定期清理已完成的任务记录,保持数据库性能。同时,合理配置任务调度频率,避免系统资源过度消耗。 + +## 故障排除指南 +当遇到任务管理相关问题时,可以按照以下步骤进行排查: +1. 检查API请求参数是否正确,特别是数据源ID和任务类型 +2. 验证数据库连接是否正常 +3. 查看服务日志,定位具体错误信息 +4. 检查任务调度配置是否符合规范 +5. 确认用户权限是否足够执行相关操作 + +常见问题包括: +- 任务创建失败:检查数据源配置和权限 +- 任务调度不执行:验证cron表达式和时间设置 +- 查询结果为空:确认数据源ID和任务类型是否匹配 +- 性能问题:检查数据库索引和系统资源使用情况 + +**章节来源** +- [CommonTaskController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskController.java#L39-L46) +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java#L50-L54) + +## 结论 +本文档详细介绍了质量检查任务管理系统的API设计和实现。系统提供了完整的任务生命周期管理功能,包括创建、更新、删除、查询和调度。通过清晰的分层架构和模块化设计,系统具有良好的可维护性和扩展性。API设计遵循RESTful规范,便于集成和使用。未来可以进一步优化性能,增加更多任务类型和检查规则,提升系统的实用性和灵活性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241\346\211\247\350\241\214API.md" "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241\346\211\247\350\241\214API.md" new file mode 100644 index 00000000..8265e287 --- /dev/null +++ "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241\346\211\247\350\241\214API.md" @@ -0,0 +1,302 @@ +# 任务执行API + + +**本文档中引用的文件** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [JobExecutionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionInfo.java) +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java) +- [JobExecutionVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionVO.java) +- [JobExecutionPageParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionPageParam.java) +- [JobExecutionDashboardParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionDashboardParam.java) +- [LogService.java](file://datavines-server/dqc/coordinator/log/LogService.java) +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java) +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java) + + +## 目录 +1. [简介](#简介) +2. [API端点概览](#api端点概览) +3. [任务执行状态机](#任务执行状态机) +4. [执行结果结构](#执行结果结构) +5. [高级查询功能](#高级查询功能) +6. [执行日志流式获取](#执行日志流式获取) +7. [性能优化建议](#性能优化建议) +8. [常见错误码与解决方案](#常见错误码与解决方案) + +## 简介 +任务执行API是DataVines平台的核心组件,用于监控和管理质量检查任务的执行过程。该API提供了完整的生命周期管理功能,包括任务提交、状态查询、执行日志获取、结果分析和历史记录查询。API设计遵循RESTful原则,通过清晰的端点划分和标准化的响应格式,为用户提供可靠的任务执行监控能力。 + +**本节来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) + +## API端点概览 +任务执行API提供了一系列RESTful端点,用于管理质量检查任务的执行过程。主要功能包括任务提交、状态查询、结果获取和日志访问。 + +### 任务提交 +用于提交新的质量检查或数据核对任务。 + +```mermaid +flowchart TD +A["POST /api/v1/job/execution/submit/data-quality"] --> B["提交质量检查任务"] +C["POST /api/v1/job/execution/submit/data-reconciliation"] --> D["提交数据核对任务"] +``` + +**端点详情:** +- **提交质量检查任务** + - HTTP方法: POST + - URL路径: `/api/v1/job/execution/submit/data-quality` + - 请求体: `SubmitJob` 对象 + - 响应: 执行实例ID + +- **提交数据核对任务** + - HTTP方法: POST + - URL路径: `/api/v1/job/execution/submit/data-reconciliation` + - 请求体: `SubmitJob` 对象 + - 响应: 执行实例ID + +### 状态管理 +提供任务状态查询和终止功能。 + +```mermaid +flowchart TD +A["GET /api/v1/job/execution/status/{executionId}"] --> B["获取执行状态"] +C["DELETE /api/v1/job/execution/kill/{executionId}"] --> D["终止执行"] +``` + +**端点详情:** +- **获取执行状态** + - HTTP方法: GET + - URL路径: `/api/v1/job/execution/status/{executionId}` + - 路径参数: `executionId` (执行实例ID) + - 响应: 状态描述字符串 + +- **终止执行** + - HTTP方法: DELETE + - URL路径: `/api/v1/job/execution/kill/{executionId}` + - 路径参数: `executionId` (执行实例ID) + - 响应: 操作结果 + +### 结果查询 +提供执行结果的详细信息查询功能。 + +```mermaid +flowchart TD +A["GET /api/v1/job/execution/list/result/{executionId}"] --> B["获取执行结果列表"] +C["GET /api/v1/job/execution/list/{jobId}"] --> D["获取作业执行列表"] +``` + +**端点详情:** +- **获取执行结果列表** + - HTTP方法: GET + - URL路径: `/api/v1/job/execution/list/result/{executionId}` + - 路径参数: `executionId` (执行实例ID) + - 响应: `JobExecutionResultVO` 列表 + +- **获取作业执行列表** + - HTTP方法: GET + - URL路径: `/api/v1/job/execution/list/{jobId}` + - 路径参数: `jobId` (作业ID) + - 响应: `JobExecution` 对象列表 + +**本节来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java) + +## 任务执行状态机 +任务执行状态机定义了执行实例的完整生命周期,从提交到完成的各个状态转换。 + +```mermaid +stateDiagram-v2 +[*] --> SUBMITTED_SUCCESS +SUBMITTED_SUCCESS --> RUNNING_EXECUTION +RUNNING_EXECUTION --> SUCCESS +RUNNING_EXECUTION --> FAILURE +RUNNING_EXECUTION --> KILL +RUNNING_EXECUTION --> STOP +READY_PAUSE --> PAUSE +PAUSE --> RUNNING_EXECUTION +READY_STOP --> STOP +WAITING_SUMMIT --> SUBMITTED_SUCCESS +SUCCESS --> [*] +FAILURE --> [*] +KILL --> [*] +STOP --> [*] +``` + +### 状态定义 +执行状态由 `ExecutionStatus` 枚举类定义,包含以下核心状态: + +| 状态代码 | 状态名称 | 描述 | +|---------|---------|------| +| 0 | SUBMITTED_SUCCESS | 已提交 | +| 1 | RUNNING_EXECUTION | 执行中 | +| 6 | FAILURE | 失败 | +| 7 | SUCCESS | 成功 | +| 9 | KILL | 强制终止 | +| 5 | STOP | 停止 | + +### 状态转换规则 +- **可终止状态**: `SUBMITTED_SUCCESS`, `READY_PAUSE`, `RUNNING_EXECUTION` +- **完成状态**: `SUCCESS`, `FAILURE`, `KILL`, `STOP` +- **运行状态**: `RUNNING_EXECUTION` +- **暂停状态**: `PAUSE` + +**本节来源** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [JobExecutionVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionVO.java) + +## 执行结果结构 +执行结果通过标准化的JSON结构返回,包含检查结果、指标信息和执行元数据。 + +### 核心字段 +```json +{ + "checkSubject": "检查主题", + "metricName": "指标名称", + "metricParameter": { + "key": "value" + }, + "checkResult": "检查结果", + "expectedType": "预期类型", + "resultFormulaFormat": "结果公式格式", + "score": 95.5, + "executionTime": "2023-01-01T12:00:00" +} +``` + +### 字段说明 +| 字段名 | 类型 | 描述 | +|-------|------|------| +| checkSubject | string | 检查的主题,如表、列等 | +| metricName | string | 指标名称,如"行数检查"、"空值检查"等 | +| metricParameter | object | 指标参数,包含具体的检查配置 | +| checkResult | string | 检查结果,如"PASS"、"FAIL"等 | +| expectedType | string | 预期值类型 | +| resultFormulaFormat | string | 结果计算公式格式 | +| score | number | 质量评分,0-100 | +| executionTime | datetime | 执行时间 | + +**本节来源** +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java) +- [JobExecutionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionInfo.java) + +## 高级查询功能 +提供分页查询、状态过滤和时间范围查询等高级功能,支持大规模执行实例的高效管理。 + +### 分页查询 +```mermaid +sequenceDiagram +客户端->>服务器 : POST /api/v1/job/execution/page +服务器->>数据库 : 查询执行实例 +数据库-->>服务器 : 返回分页结果 +服务器-->>客户端 : 返回执行实例列表 +``` + +**请求参数 (JobExecutionPageParam):** +- `pageNumber`: 页码 (从1开始) +- `pageSize`: 每页大小 +- `jobId`: 作业ID (可选) +- `status`: 执行状态 (可选) +- `startTime`: 开始时间 (可选) +- `endTime`: 结束时间 (可选) +- `searchVal`: 搜索关键词 (可选) + +### 聚合查询 +提供执行状态的聚合统计和趋势分析。 + +```mermaid +flowchart TD +A["POST /api/v1/job/execution/agg-pie"] --> B["获取状态聚合饼图"] +C["POST /api/v1/job/execution/trend-bar"] --> D["获取趋势柱状图"] +``` + +**聚合参数 (JobExecutionDashboardParam):** +- `workspaceId`: 工作空间ID +- `startTime`: 开始时间 +- `endTime`: 结束时间 +- `jobType`: 作业类型 (可选) + +**本节来源** +- [JobExecutionPageParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionPageParam.java) +- [JobExecutionDashboardParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionDashboardParam.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) + +## 执行日志流式获取 +提供执行日志的流式获取功能,支持实时日志查看和文件下载。 + +### 实时日志查询 +```mermaid +sequenceDiagram +客户端->>服务器 : GET /api/v1/history/job/execution/queryLogWithOffsetLine +服务器->>日志服务 : 查询日志 +日志服务-->>服务器 : 返回日志行 +服务器-->>客户端 : 返回日志内容 +``` + +**端点详情:** +- HTTP方法: GET +- URL路径: `/api/v1/history/job/execution/queryLogWithOffsetLine` +- 请求参数: + - `taskId`: 任务ID + - `offsetLine`: 偏移行数 +- 响应: 日志内容数组 + +### 日志文件下载 +```mermaid +flowchart TD +A["GET /api/v1/history/job/execution/download"] --> B["重定向到执行主机"] +B --> C["下载日志文件"] +``` + +**端点详情:** +- HTTP方法: GET +- URL路径: `/api/v1/history/job/execution/download` +- 请求参数: `taskId` (任务ID) +- 响应: 日志文件流 + +**本节来源** +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [LogService.java](file://datavines-server/dqc/coordinator/log/LogService.java) +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java) + +## 性能优化建议 +为确保API在大规模场景下的性能表现,提供以下优化建议。 + +### 大结果集处理 +- **分页查询**: 使用分页参数避免一次性获取过多数据 +- **字段过滤**: 只请求必要的字段,减少网络传输 +- **缓存策略**: 对频繁查询的结果进行客户端缓存 + +### 批量操作 +- **批量查询**: 使用聚合查询接口获取多个执行实例的统计信息 +- **异步处理**: 对于耗时操作,考虑使用异步API模式 + +### 连接管理 +- **连接复用**: 使用HTTP连接池复用连接 +- **超时设置**: 合理设置连接和读取超时 +- **重试机制**: 实现指数退避重试策略 + +**本节来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java) + +## 常见错误码与解决方案 +列出常见的API错误码及其解决方案。 + +| 错误码 | 错误信息 | 原因 | 解决方案 | +|-------|--------|------|---------| +| 30404 | 任务不存在 | 提供的执行ID无效 | 检查执行ID是否正确 | +| 50001 | 任务执行主机不存在 | 无法确定任务执行主机 | 检查任务状态和配置 | +| 50002 | 任务日志路径不存在 | 日志文件未生成或路径错误 | 检查日志配置和文件系统 | +| 40001 | 请求参数无效 | 提交的参数不符合验证规则 | 检查请求体格式和必填字段 | +| 50003 | 任务已终止 | 尝试操作已终止的任务 | 检查任务当前状态 | + +**本节来源** +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [DataVinesServerException.java](file://datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241\347\256\241\347\220\206API.md" "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241\347\256\241\347\220\206API.md" new file mode 100644 index 00000000..5e3853ec --- /dev/null +++ "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241\347\256\241\347\220\206API.md" @@ -0,0 +1,254 @@ +# 任务管理API + + +**本文档引用的文件** +- [CommonTaskController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskController.java) +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java) +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) +- [JobUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobUpdate.java) +- [CommonTaskScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/task/CommonTaskScheduleCreateOrUpdate.java) +- [JobVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobVO.java) + + +## 目录 +1. [简介](#简介) +2. [任务生命周期管理API](#任务生命周期管理api) +3. [任务配置结构](#任务配置结构) +4. [不同类型任务的配置示例](#不同类型任务的配置示例) +5. [高级功能API](#高级功能api) +6. [任务状态转换](#任务状态转换) +7. [常见错误码与解决方案](#常见错误码与解决方案) + +## 简介 +本API文档详细描述了质量检查任务的全生命周期管理功能,涵盖任务的创建、更新、删除、查询和克隆等核心操作。系统支持多种类型的数据质量检查任务,包括单表检查、跨表检查和数据画像等场景。通过RESTful接口提供完整的任务管理能力,支持灵活的检查规则配置、预期值设置和通知策略定义。API设计遵循标准HTTP协议规范,使用JSON格式进行数据交换,确保接口的易用性和可集成性。 + +## 任务生命周期管理API + +### 创建质量检查任务 +通过POST请求创建新的质量检查任务,需要提供完整的任务配置信息。 + +**HTTP方法**: POST +**URL路径**: `/api/v1/job` +**请求体结构**: 包含任务类型、数据源ID、执行平台参数、引擎类型、超时设置等配置项 + +```json +{ + "type": "single_table", + "dataSourceId": 123, + "engineType": "local", + "parameter": "{\"metricType\":\"row_count\",\"expectedValue\":1000}", + "jobName": "订单表行数检查" +} +``` + +**Section sources** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L45-L49) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java#L27-L78) + +### 更新质量检查任务 +通过PUT请求更新现有质量检查任务的配置。 + +**HTTP方法**: PUT +**URL路径**: `/api/v1/job` +**请求体结构**: 包含任务ID和其他需要更新的字段 + +```json +{ + "id": 456, + "type": "single_table", + "dataSourceId": 123, + "parameter": "{\"metricType\":\"row_count\",\"expectedValue\":2000}", + "jobName": "更新后的订单表行数检查" +} +``` + +**Section sources** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L57-L60) +- [JobUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobUpdate.java#L27-L31) + +### 删除质量检查任务 +通过DELETE请求删除指定ID的质量检查任务。 + +**HTTP方法**: DELETE +**URL路径**: `/api/v1/job/{id}` +**路径参数**: `id` - 任务唯一标识符 + +**Section sources** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L51-L55) + +### 查询质量检查任务 +通过GET请求查询单个或多个质量检查任务的详细信息。 + +**HTTP方法**: GET +**URL路径**: +- `/api/v1/job/{id}` - 查询单个任务 +- `/api/v1/job/page` - 分页查询任务列表 + +**查询参数**: 支持按数据源ID、任务名称、时间范围等条件进行筛选 + +**Section sources** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L63-L91) +- [JobVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobVO.java#L28-L84) + +## 任务配置结构 + +### 核心配置字段 +质量检查任务的配置采用JSON结构,包含以下核心字段: + +| 字段名称 | 类型 | 必填 | 描述 | +|---------|------|------|------| +| type | string | 是 | 任务类型,如single_table、cross_table等 | +| dataSourceId | long | 是 | 数据源ID | +| engineType | string | 否 | 执行引擎类型,如local、spark等 | +| parameter | string | 是 | 任务参数JSON字符串 | +| timeout | int | 否 | 超时时间(毫秒) | +| jobName | string | 否 | 任务名称 | + +### 数据源选择配置 +通过`dataSourceId`和`dataSourceId2`字段指定数据源,支持单数据源和双数据源场景。 + +### 检查规则配置 +在`parameter`字段中定义具体的检查规则,包含指标类型、阈值、比较方式等。 + +### 预期值设置 +支持多种预期值策略,包括固定值、历史平均值、动态计算值等。 + +### 通知策略 +可配置任务执行结果的通知方式和接收人。 + +**Section sources** +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java#L27-L78) + +## 不同类型任务的配置示例 + +### 单表检查任务 +用于检查单个数据表的质量指标。 + +```json +{ + "type": "single_table", + "dataSourceId": 123, + "parameter": { + "metricType": "row_count", + "expectedValue": 1000, + "tolerance": 0.1 + }, + "jobName": "用户表行数检查" +} +``` + +### 跨表检查任务 +用于比较两个数据表之间的数据一致性。 + +```json +{ + "type": "cross_table", + "dataSourceId": 123, + "dataSourceId2": 456, + "parameter": { + "metricType": "data_accuracy", + "comparisonField": "user_id", + "tolerance": 0.05 + }, + "jobName": "用户数据一致性检查" +} +``` + +### 数据画像任务 +用于生成数据表的统计特征和质量报告。 + +```json +{ + "type": "data_profile", + "dataSourceId": 123, + "parameter": { + "profileFields": ["name", "email", "phone"], + "statistics": ["count", "null_rate", "distinct_count"] + }, + "jobName": "用户表数据画像" +} +``` + +**Section sources** +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java#L27-L78) + +## 高级功能API + +### 任务克隆 +通过复制现有任务的配置创建新任务,支持快速批量创建相似任务。 + +**HTTP方法**: POST +**URL路径**: `/api/v1/job/clone` +**请求体**: 包含源任务ID和新任务的基本信息 + +### 批量操作 +支持批量创建、更新和删除质量检查任务。 + +**HTTP方法**: POST +**URL路径**: `/api/v1/job/batch` +**请求体**: 包含多个任务配置的数组 + +### 任务调度配置 +管理任务的定时执行计划。 + +**HTTP方法**: POST +**URL路径**: `/api/v1/common-task/schedule/createOrUpdate` +**请求体结构**: +```json +{ + "taskType": "SINGLE_TABLE", + "dataSourceId": 123, + "type": "CRON", + "param": { + "cycle": "DAILY", + "time": "02:00" + } +} +``` + +**Section sources** +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java#L44-L47) +- [CommonTaskScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/task/CommonTaskScheduleCreateOrUpdate.java#L30-L50) + +## 任务状态转换 + +### 状态转换流程 +```mermaid +stateDiagram-v2 +[*] --> 待执行 +待执行 --> 执行中 : 任务触发 +执行中 --> 执行成功 : 检查通过 +执行中 --> 执行失败 : 检查不通过 +执行中 --> 已超时 : 超过设定时间 +执行成功 --> 待执行 : 定时任务 +执行失败 --> 待执行 : 定时任务 +已超时 --> 待执行 : 定时任务 +``` + +**Diagram sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L73-L77) + +### 状态查询API +获取任务执行状态。 + +**HTTP方法**: GET +**URL路径**: `/api/v1/job/execution/status/{executionId}` +**响应**: 返回任务的当前状态描述 + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L73-L77) + +## 常见错误码与解决方案 + +| 错误码 | 描述 | 解决方案 | +|-------|------|---------| +| 400 | 请求参数无效 | 检查请求体中的必填字段是否完整,参数格式是否正确 | +| 404 | 任务不存在 | 确认任务ID是否正确,任务是否已被删除 | +| 422 | 任务配置冲突 | 检查数据源连接状态,确认配置参数的合理性 | +| 500 | 服务器内部错误 | 联系系统管理员,检查服务运行状态 | + +**Section sources** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241\350\260\203\345\272\246API.md" "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241\350\260\203\345\272\246API.md" new file mode 100644 index 00000000..5f1a7dd4 --- /dev/null +++ "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241API/\344\273\273\345\212\241\350\260\203\345\272\246API.md" @@ -0,0 +1,501 @@ +# 任务调度API + + +**本文档中引用的文件** +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java) +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java) +- [JobScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/schedule/JobScheduleCreateOrUpdate.java) +- [CommonTaskScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/task/CommonTaskScheduleCreateOrUpdate.java) +- [JobScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobScheduleService.java) +- [CommonTaskScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskScheduleService.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [MapParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/schedule/MapParam.java) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java) + + +## 目录 +1. [简介](#简介) +2. [任务调度API概览](#任务调度api概览) +3. [核心调度配置结构](#核心调度配置结构) +4. [任务调度API端点](#任务调度api端点) +5. [通用任务调度API端点](#通用任务调度api端点) +6. [Cron表达式配置与验证](#cron表达式配置与验证) +7. [调度状态转换逻辑](#调度状态转换逻辑) +8. [高级特性](#高级特性) +9. [常见错误码与解决方案](#常见错误码与解决方案) + +## 简介 +本技术文档全面记录了DataVines平台中与质量检查任务调度配置相关的RESTful接口。文档详细描述了创建、更新、启用、禁用和查询任务调度计划的API端点,包括HTTP方法、URL路径、请求参数和请求体结构。文档化了调度配置的完整JSON结构,涵盖cron表达式、调度类型、启动时间、结束时间等核心字段。提供了基于Quartz的cron表达式配置示例和最佳实践。解释了调度状态的转换逻辑和相应的API调用方式,包括调度暂停、恢复和立即触发执行的功能。包含了调度冲突检测、重叠处理等高级特性的说明,以及常见错误码和解决方案。 + +## 任务调度API概览 +DataVines平台提供了两套独立但结构相似的任务调度API,分别用于管理质量检查作业调度和通用任务调度。质量检查作业调度API主要管理数据质量检查任务的执行计划,而通用任务调度API则用于管理元数据抓取、数据质量报告生成等系统级任务。两套API均基于Quartz调度框架实现,支持灵活的cron表达式配置,允许用户定义复杂的调度周期。 + +**调度系统架构** +```mermaid +graph TB +subgraph "客户端" +UI[用户界面] +API_Client[API客户端] +end +subgraph "服务端" +API_Server[API服务器] +Scheduler[Quartz调度器] +Database[(数据库)] +end +UI --> API_Server +API_Client --> API_Server +API_Server --> Scheduler +API_Server --> Database +Scheduler --> Database +``` + +**图源** +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) + +## 核心调度配置结构 +调度配置的核心结构包含多个关键字段,这些字段共同定义了任务的执行行为和周期。所有调度配置均通过JSON格式的请求体进行传输,支持灵活的参数化配置。 + +### 质量检查任务调度配置 +质量检查任务调度配置主要用于定义数据质量检查作业的执行计划。配置结构继承自`JobScheduleCreate`类,并包含一个可选的ID字段用于更新操作。 + +```json +{ + "id": 123, + "jobId": 456, + "type": "CRON", + "param": { + "cycle": "custom", + "parameter": { + "crontab": "0 0 2 * * ?" + } + }, + "startTime": "2023-01-01 00:00:00", + "endTime": "2024-01-01 00:00:00" +} +``` + +**字段说明** +- `id`: 调度配置的唯一标识符,创建新调度时可为空 +- `jobId`: 关联的质量检查作业ID,必填字段 +- `type`: 调度类型,目前支持"CRON"类型 +- `param`: 调度参数,包含调度周期和具体参数 +- `startTime`: 调度开始时间,ISO 8601格式 +- `endTime`: 调度结束时间,可为空表示无限期执行 + +**节源** +- [JobScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/schedule/JobScheduleCreateOrUpdate.java) +- [JobScheduleCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/schedule/JobScheduleCreate.java) + +### 通用任务调度配置 +通用任务调度配置用于管理平台级任务的执行计划,如元数据抓取和数据质量报告生成。与质量检查任务调度相比,通用任务调度配置包含任务类型字段,用于区分不同类型的系统任务。 + +```json +{ + "id": 789, + "taskType": "CATALOG_METADATA_FETCH", + "dataSourceId": 101, + "type": "CRON", + "param": { + "cycle": "daily", + "parameter": { + "hour": "2", + "minute": "0" + } + }, + "startTime": "2023-01-01 00:00:00", + "endTime": "2024-01-01 00:00:00" +} +``` + +**字段说明** +- `taskType`: 任务类型,枚举值包括"CATALOG_METADATA_FETCH"和"DATA_QUALITY_REPORT" +- `dataSourceId`: 关联的数据源ID,必填字段 +- 其他字段与质量检查任务调度配置相同 + +**节源** +- [CommonTaskScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/task/CommonTaskScheduleCreateOrUpdate.java) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java) + +## 任务调度API端点 +任务调度API提供了一组RESTful端点,用于管理质量检查作业的调度配置。所有端点均位于`/api/v1/job/schedule`基础路径下,需要有效的身份验证令牌。 + +### 创建或更新调度配置 +该端点用于创建新的质量检查作业调度配置或更新现有配置。如果请求中包含ID且该ID对应的调度配置已存在,则执行更新操作;否则创建新的调度配置。 + +**API详情** +- **HTTP方法**: POST +- **URL路径**: `/api/v1/job/schedule/createOrUpdate` +- **请求内容类型**: `application/json` +- **响应内容类型**: `application/json` + +**请求体结构** +```json +{ + "jobId": 456, + "type": "CRON", + "param": { + "cycle": "custom", + "parameter": { + "crontab": "0 0 2 * * ?" + } + }, + "startTime": "2023-01-01 00:00:00", + "endTime": "2024-01-01 00:00:00" +} +``` + +**成功响应** +```json +{ + "success": true, + "msg": "操作成功", + "data": { + "id": 123, + "jobId": 456, + "type": "CRON", + "param": { + "cycle": "custom", + "parameter": { + "crontab": "0 0 2 * * ?" + } + }, + "startTime": "2023-01-01 00:00:00", + "endTime": "2024-01-01 00:00:00", + "createTime": "2023-01-01 10:00:00", + "updateTime": "2023-01-01 10:00:00" + } +} +``` + +**节源** +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java#L46-L50) +- [JobScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobScheduleService.java#L30) + +### 查询作业调度配置 +该端点用于根据作业ID查询对应的质量检查作业调度配置。如果指定作业没有配置调度计划,则返回空结果。 + +**API详情** +- **HTTP方法**: GET +- **URL路径**: `/api/v1/job/schedule/{jobId}` +- **响应内容类型**: `application/json` + +**路径参数** +- `jobId`: 质量检查作业的唯一标识符 + +**成功响应** +```json +{ + "success": true, + "msg": "操作成功", + "data": { + "id": 123, + "jobId": 456, + "type": "CRON", + "param": { + "cycle": "custom", + "parameter": { + "crontab": "0 0 2 * * ?" + } + }, + "startTime": "2023-01-01 00:00:00", + "endTime": "2024-01-01 00:00:00", + "createTime": "2023-01-01 10:00:00", + "updateTime": "2023-01-01 10:00:00" + } +} +``` + +**节源** +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java#L52-L56) +- [JobScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobScheduleService.java#L38) + +## 通用任务调度API端点 +通用任务调度API提供了一组RESTful端点,用于管理平台级任务的调度配置。所有端点均位于`/api/v1/common-task/schedule`基础路径下,需要有效的身份验证令牌。 + +### 创建或更新通用任务调度 +该端点用于创建新的通用任务调度配置或更新现有配置。与质量检查任务调度类似,如果请求中包含ID且该ID对应的调度配置已存在,则执行更新操作;否则创建新的调度配置。 + +**API详情** +- **HTTP方法**: POST +- **URL路径**: `/api/v1/common-task/schedule/createOrUpdate` +- **请求内容类型**: `application/json` +- **响应内容类型**: `application/json` + +**请求体结构** +```json +{ + "taskType": "CATALOG_METADATA_FETCH", + "dataSourceId": 101, + "type": "CRON", + "param": { + "cycle": "daily", + "parameter": { + "hour": "2", + "minute": "0" + } + }, + "startTime": "2023-01-01 00:00:00", + "endTime": "2024-01-01 00:00:00" +} +``` + +**成功响应** +```json +{ + "success": true, + "msg": "操作成功", + "data": { + "id": 789, + "taskType": "CATALOG_METADATA_FETCH", + "dataSourceId": 101, + "type": "CRON", + "param": { + "cycle": "daily", + "parameter": { + "hour": "2", + "minute": "0" + } + }, + "startTime": "2023-01-01 00:00:00", + "endTime": "2024-01-01 00:00:00", + "createTime": "2023-01-01 10:00:00", + "updateTime": "2023-01-01 10:00:00" + } +} +``` + +**节源** +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java#L44-L48) +- [CommonTaskScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskScheduleService.java#L30) + +### 根据数据源ID查询通用任务调度 +该端点用于根据数据源ID和任务类型查询对应的通用任务调度配置。此查询方式特别适用于需要获取特定数据源上某种类型任务调度配置的场景。 + +**API详情** +- **HTTP方法**: GET +- **URL路径**: `/api/v1/common-task/schedule/{dataSourceId}/{taskType}` +- **响应内容类型**: `application/json` + +**路径参数** +- `dataSourceId`: 数据源的唯一标识符 +- `taskType`: 任务类型,可选值为"CATALOG_METADATA_FETCH"或"DATA_QUALITY_REPORT" + +**成功响应** +```json +{ + "success": true, + "msg": "操作成功", + "data": { + "id": 789, + "taskType": "CATALOG_METADATA_FETCH", + "dataSourceId": 101, + "type": "CRON", + "param": { + "cycle": "daily", + "parameter": { + "hour": "2", + "minute": "0" + } + }, + "startTime": "2023-01-01 00:00:00", + "endTime": "2024-01-01 00:00:00", + "createTime": "2023-01-01 10:00:00", + "updateTime": "2023-01-01 10:00:00" + } +} +``` + +**节源** +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java#L50-L54) +- [CommonTaskScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CommonTaskScheduleService.java#L38) + +## Cron表达式配置与验证 +Cron表达式是任务调度系统的核心组成部分,用于定义任务执行的复杂时间周期。DataVines平台基于Quartz调度框架,支持完整的cron表达式语法。 + +### Cron表达式生成 +系统提供了辅助API端点,用于根据简单的周期参数生成对应的cron表达式。这简化了用户配置复杂调度周期的过程。 + +**API详情** +- **HTTP方法**: POST +- **URL路径**: `/api/v1/job/schedule/cron` 和 `/api/v1/common-task/schedule/cron` +- **请求内容类型**: `application/json` +- **响应内容类型**: `application/json` + +**请求体结构** +```json +{ + "cycle": "weekly", + "parameter": { + "dayOfWeek": "1", + "hour": "2", + "minute": "30" + } +} +``` + +**成功响应** +```json +{ + "success": true, + "msg": "操作成功", + "data": ["0 30 2 ? * 1"] +} +``` + +**节源** +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java#L58-L62) +- [CommonTaskScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CommonTaskScheduleController.java#L56-L60) +- [MapParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/schedule/MapParam.java) + +### Cron表达式验证 +在创建或更新调度配置时,系统会自动验证cron表达式的有效性。用户也可以通过专门的API端点来验证cron表达式。 + +**API详情** +- **HTTP方法**: POST +- **URL路径**: `/api/v1/job/schedule/cron/future/list` +- **请求内容类型**: `application/json` +- **响应内容类型**: `application/json` + +**请求体结构** +```json +{ + "crontab": "0 0 2 * * ?" +} +``` + +**成功响应** +```json +{ + "success": true, + "msg": "操作成功", + "data": [ + "2023-01-02 02:00:00", + "2023-01-03 02:00:00", + "2023-01-04 02:00:00", + "2023-01-05 02:00:00", + "2023-01-06 02:00:00" + ] +} +``` + +**节源** +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java#L65-L69) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L239-L263) + +## 调度状态转换逻辑 +调度系统的状态转换主要通过创建、更新和删除操作来实现。系统本身不提供显式的启用/禁用端点,而是通过调度配置的生命周期管理来控制任务的执行状态。 + +### 调度创建与启用 +当创建新的调度配置时,系统会自动将其注册到Quartz调度器中,从而使任务进入可执行状态。调度配置中的`startTime`字段定义了任务首次执行的时间。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant API as "API服务器" +participant Scheduler as "Quartz调度器" +Client->>API : POST /api/v1/job/schedule/createOrUpdate +API->>API : 验证请求参数 +API->>API : 构建调度信息 +API->>Scheduler : 添加作业和触发器 +Scheduler-->>API : 注册成功 +API-->>Client : 返回创建的调度配置 +``` + +**图源** +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java#L46-L50) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L74-L149) + +### 调度更新与修改 +更新现有调度配置时,系统会检查cron表达式是否发生变化。如果发生变化,系统会重新安排触发器,从而修改任务的执行周期。`startTime`和`endTime`字段的修改也会相应调整任务的执行时间窗口。 + +### 调度删除与禁用 +删除调度配置是禁用任务执行的主要方式。当删除调度配置时,系统会从Quartz调度器中移除对应的作业和触发器,从而停止任务的后续执行。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant API as "API服务器" +participant Scheduler as "Quartz调度器" +Client->>API : DELETE /api/v1/job/schedule/{id} +API->>API : 查找调度配置 +API->>Scheduler : 删除作业 +Scheduler-->>API : 删除成功 +API->>API : 从数据库删除记录 +API-->>Client : 返回删除成功 +``` + +**节源** +- [JobScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobScheduleService.java#L32) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L157-L174) + +## 高级特性 +任务调度系统提供了一些高级特性,以满足复杂的调度需求和提高系统的可靠性。 + +### 调度冲突检测 +系统在创建或更新调度配置时会自动检测潜在的调度冲突。虽然当前实现中没有显式的冲突检测逻辑,但通过唯一的工作名称和组名称组合(基于任务类型、ID和数据源ID生成),确保了每个调度配置的唯一性。 + +```java +private static String buildJobName(ScheduleJobInfo schedule) { + return schedule.getType().getDescription() + "_job" + DataVinesConstants.UNDERLINE + schedule.getId(); +} + +private static String buildJobGroupName(ScheduleJobInfo schedule) { + return schedule.getType().getDescription() + "_job_group" + DataVinesConstants.UNDERLINE + schedule.getDatasourceId(); +} +``` + +**节源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L204-L215) + +### 时区处理 +系统在处理调度时间时会进行时区转换,确保调度时间在不同服务器时区环境下的一致性。当将调度信息添加到Quartz调度器时,系统会将本地时间转换为服务器默认时区的时间。 + +```java +private static Date buildDate(LocalDateTime localDateTime){ + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId); + Instant instant = zonedDateTime.toInstant(); + return Date.from(instant); +} +``` + +**节源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L232-L237) + +## 常见错误码与解决方案 +以下是任务调度API中常见的错误码及其解决方案。 + +### SCHEDULE_CRON_IS_INVALID_ERROR +**错误描述**: 提供的cron表达式无效 +**错误码**: 4001 +**解决方案**: +1. 检查cron表达式的格式是否符合Quartz cron表达式规范 +2. 使用`/cron/future/list`端点验证cron表达式 +3. 参考标准cron表达式语法:`秒 分 时 日 月 周 年(可选)` + +### JOB_ID_CANNOT_BE_EMPTY +**错误描述**: 作业ID不能为空 +**错误码**: 4002 +**解决方案**: +1. 确保在创建调度配置时提供了有效的作业ID +2. 通过作业管理API获取有效的作业ID列表 + +### DATASOURCE_ID_CANNOT_BE_EMPTY +**错误描述**: 数据源ID不能为空 +**错误码**: 4003 +**解决方案**: +1. 确保在创建通用任务调度时提供了有效的数据源ID +2. 通过数据源管理API获取有效的数据源ID列表 + +### TASK_TYPE_CANNOT_BE_EMPTY +**错误描述**: 任务类型不能为空 +**错误码**: 4004 +**解决方案**: +1. 确保在创建通用任务调度时提供了有效的任务类型 +2. 使用支持的任务类型:`CATALOG_METADATA_FETCH`或`DATA_QUALITY_REPORT` + +**节源** +- [JobScheduleCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/schedule/JobScheduleCreate.java#L30-L31) +- [CommonTaskScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/task/CommonTaskScheduleCreateOrUpdate.java#L34-L38) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L253-L258) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241\346\211\247\350\241\214API.md" "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241\346\211\247\350\241\214API.md" new file mode 100644 index 00000000..643a51a2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\344\273\273\345\212\241\346\211\247\350\241\214API.md" @@ -0,0 +1,313 @@ +# 任务执行API + + +**本文档中引用的文件** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java) +- [JobExecutionPageParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionPageParam.java) +- [JobExecutionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionInfo.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java) +- [LogResult.java](file://datavines-common/src/main/java/io/datavines/common/entity/LogResult.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录)(如有必要) + +## 简介 +本文档全面记录了与任务执行实例相关的所有RESTful接口,重点描述了查询任务执行历史、获取执行日志、查看执行结果和检查详细报告的API端点。文档详细说明了执行结果的JSON结构,包括总体执行状态、各检查项结果、错误数据详情等。同时提供了分页查询、条件过滤等高级查询功能的使用方法,解释了执行结果中各项指标的含义和计算方式,并包含执行日志流式获取的API使用示例,为监控系统集成提供指导。 + +## 项目结构 +DataVines项目是一个大数据质量监控系统,其任务执行API主要集中在`datavines-server`模块中。该模块提供了RESTful接口来管理任务的执行、查询执行历史、获取执行日志和查看执行结果。`datavines-common`模块包含了任务执行相关的公共实体和枚举,而`datavines-metric`模块则定义了质量检查的度量标准和结果计算。 + +```mermaid +graph TB +subgraph "前端" +UI[用户界面] +end +subgraph "后端" +API[任务执行API] +Service[任务执行服务] +Repository[数据访问层] +Log[日志服务] +end +UI --> API +API --> Service +Service --> Repository +Service --> Log +``` + +**图表来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) + +**章节来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) + +## 核心组件 +任务执行API的核心组件包括`JobExecutionController`、`JobHistoryExecutionController`和`JobQualityReportController`。这些控制器提供了对任务执行生命周期的全面管理,从提交任务到查询执行结果和日志。`JobExecutionController`负责任务的提交、状态查询和执行列表获取;`JobHistoryExecutionController`提供了对执行日志的流式查询和下载功能;`JobQualityReportController`则专注于质量报告的生成和查询。 + +**章节来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) + +## 架构概述 +任务执行API采用典型的分层架构,包括控制器层、服务层和数据访问层。控制器层暴露RESTful接口,服务层处理业务逻辑,数据访问层与数据库交互。日志服务独立于主流程,通过异步方式收集和查询任务执行日志。这种架构确保了系统的可扩展性和可维护性。 + +```mermaid +graph TB +Client[客户端] --> Controller[控制器层] +Controller --> Service[服务层] +Service --> Repository[数据访问层] +Service --> LogService[日志服务] +Repository --> Database[(数据库)] +LogService --> LogFile[(日志文件)] +``` + +**图表来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java) + +## 详细组件分析 + +### 任务执行控制器分析 +`JobExecutionController`是任务执行API的主要入口,提供了任务提交、状态查询和执行列表获取等功能。该控制器通过`JobExecutionService`处理业务逻辑,并返回相应的执行结果。 + +#### 类图 +```mermaid +classDiagram +class JobExecutionController { ++jobExecutionService JobExecutionService ++jobExecutionResultService JobExecutionResultService ++jobExecutionErrorDataService JobExecutionErrorDataService ++submitDataQualityJob(SubmitJob) Object ++submitDataReconJob(SubmitJob) Object ++killTask(Long) Object ++getTaskStatus(Long) Object ++getJobExecutionListByJobId(Long) Object ++getJobExecutionResultInfoList(Long) Object ++page(JobExecutionPageParam) Object ++readErrorDataPage(Long, Integer, Integer) Object ++getExecutionAggPie(JobExecutionDashboardParam) Object ++getExecutionTrendBar(JobExecutionDashboardParam) Object +} +class JobExecutionService { ++submitJob(SubmitJob) Long ++killJob(Long) Boolean ++getById(Long) JobExecution ++listByJobId(Long) JobExecution[] ++getJobExecutionPage(JobExecutionPageParam) IPage~JobExecutionVO~ ++getJobExecutionAggPie(JobExecutionDashboardParam) JobExecutionAggItem[] ++getJobExecutionTrendBar(JobExecutionDashboardParam) JobExecutionTrendBar +} +JobExecutionController --> JobExecutionService : "依赖" +``` + +**图表来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) + +#### 序列图 +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "JobExecutionController" +participant Service as "JobExecutionService" +participant Repository as "JobExecutionMapper" +Client->>Controller : POST /api/v1/job/execution/submit/data-quality +Controller->>Service : submitJob(SubmitJob) +Service->>Repository : insert(JobExecution) +Repository-->>Service : 执行ID +Service-->>Controller : 执行ID +Controller-->>Client : {executionId} +Client->>Controller : GET /api/v1/job/execution/status/{executionId} +Controller->>Service : getById(executionId) +Service->>Repository : selectById(executionId) +Repository-->>Service : JobExecution +Service-->>Controller : ExecutionStatus +Controller-->>Client : {status} +``` + +**图表来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) +- [JobExecutionMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobExecutionMapper.java) + +**章节来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) + +### 任务历史执行控制器分析 +`JobHistoryExecutionController`提供了对任务执行日志的查询和下载功能。该控制器通过`LogService`查询日志内容,并支持按偏移行数流式获取日志。 + +#### 类图 +```mermaid +classDiagram +class JobHistoryExecutionController { ++jobExecutionService JobExecutionService ++logService LogService ++queryLogWithOffsetLine(Long, int) Object ++download(Long) void +} +class LogService { ++queryLog(long, int, int) LogResult ++getLogBytes(long) byte[] +} +JobHistoryExecutionController --> LogService : "依赖" +JobHistoryExecutionController --> JobExecutionService : "依赖" +``` + +**图表来源** +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java) + +#### 序列图 +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "JobHistoryExecutionController" +participant LogService as "LogService" +Client->>Controller : GET /api/v1/history/job/execution/queryLogWithOffsetLine +Controller->>Controller : getJobExecutionHost(taskId) +Controller->>LogService : queryLog(taskId, offsetLine, 10000) +LogService->>LogService : readPartFileContent(logPath, offsetLine, 10000) +LogService-->>Controller : LogResult +Controller-->>Client : {msg, offsetLine} +``` + +**图表来源** +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java) + +**章节来源** +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java) + +### 任务质量报告控制器分析 +`JobQualityReportController`提供了对任务质量报告的查询功能,包括分页查询、分数查询和趋势查询。 + +#### 类图 +```mermaid +classDiagram +class JobQualityReportController { ++jobExecutionService JobExecutionService ++jobExecutionResultService JobExecutionResultService ++jobExecutionErrorDataService JobExecutionErrorDataService ++jobQualityReportService JobQualityReportService ++page(JobQualityReportDashboardParam) Object ++listColumnExecution(Long) Object ++getScoreByCondition(JobQualityReportDashboardParam) Object ++getScoreTrendByCondition(JobQualityReportDashboardParam) Object +} +class JobQualityReportService { ++getQualityReportPage(JobQualityReportDashboardParam) IPage~JobExecutionResultVO~ ++listColumnExecution(Long) JobExecutionResultVO[] ++getScoreByCondition(JobQualityReportDashboardParam) BigDecimal ++getScoreTrendByCondition(JobQualityReportDashboardParam) JobQualityReportScoreTrend[] +} +JobQualityReportController --> JobQualityReportService : "依赖" +``` + +**图表来源** +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) +- [JobQualityReportService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobQualityReportService.java) + +**章节来源** +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) +- [JobQualityReportService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobQualityReportService.java) + +## 依赖分析 +任务执行API的依赖关系清晰,控制器层依赖于服务层,服务层依赖于数据访问层和日志服务。这种分层依赖确保了各组件的职责分离和可测试性。 + +```mermaid +graph TD +JobExecutionController --> JobExecutionService +JobHistoryExecutionController --> LogService +JobHistoryExecutionController --> JobExecutionService +JobQualityReportController --> JobQualityReportService +JobExecutionService --> JobExecutionMapper +JobQualityReportService --> JobExecutionResultMapper +LogService --> JobExecutionMapper +``` + +**图表来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) +- [JobQualityReportService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobQualityReportService.java) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java) + +**章节来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) + +## 性能考虑 +任务执行API在设计时考虑了性能因素。日志查询采用流式读取,避免了大文件加载到内存中。分页查询和条件过滤功能减少了不必要的数据传输。对于高频查询的执行状态,可以考虑引入缓存机制以进一步提升性能。 + +## 故障排除指南 +当任务执行API出现问题时,可以按照以下步骤进行排查: +1. 检查任务执行状态是否为"失败"或"强制终止"。 +2. 查询执行日志以获取详细的错误信息。 +3. 检查数据库连接和任务配置是否正确。 +4. 验证执行主机是否可达。 + +**章节来源** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobHistoryExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java) + +## 结论 +任务执行API为DataVines系统提供了全面的任务管理功能,包括任务提交、状态查询、日志获取和质量报告生成。通过RESTful接口,外部系统可以方便地集成和监控数据质量检查任务。API设计合理,性能良好,为大数据质量监控提供了可靠的基础。 + +## 附录 + +### 执行状态枚举 +任务执行状态枚举定义了任务的生命周期状态: + +| 状态码 | 英文描述 | 中文描述 | +|--------|----------|----------| +| 0 | submitted | 已提交 | +| 1 | running | 执行中 | +| 6 | failure | 失败 | +| 7 | success | 成功 | +| 9 | kill | 强制终止 | + +**章节来源** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) + +### 执行结果VO +任务执行结果的JSON结构如下: + +```json +{ + "checkSubject": "检查主题", + "metricName": "度量名称", + "metricParameter": { + "key": "value" + }, + "checkResult": "检查结果", + "expectedType": "期望类型", + "resultFormulaFormat": "结果公式格式", + "score": 95.5, + "executionTime": "2023-01-01T12:00:00" +} +``` + +**章节来源** +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\345\267\245\344\275\234\347\251\272\351\227\264API.md" "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\345\267\245\344\275\234\347\251\272\351\227\264API.md" new file mode 100644 index 00000000..44306110 --- /dev/null +++ "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\345\267\245\344\275\234\347\251\272\351\227\264API.md" @@ -0,0 +1,247 @@ +# 工作空间API + + +**本文档中引用的文件** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java) +- [WorkSpaceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceCreate.java) +- [WorkSpaceUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceUpdate.java) +- [InviteUserIntoWorkspace.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/InviteUserIntoWorkspace.java) +- [RemoveUserOutWorkspace.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/RemoveUserOutWorkspace.java) +- [WorkSpaceVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/WorkSpaceVO.java) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java) +- [WorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/WorkSpaceServiceImpl.java) +- [WorkSpaceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/WorkSpaceMapper.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [UserWorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/UserWorkSpaceService.java) +- [UserWorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserWorkSpaceServiceImpl.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档全面记录了DataVines平台中与工作空间管理相关的所有RESTful接口。文档详细描述了创建、更新、删除工作空间以及管理用户与工作空间关系的API端点。同时,文档化了工作空间配置的JSON结构,包括名称、描述、成员管理等,并解释了工作空间隔离机制和资源分配策略。此外,还提供了批量用户管理、权限分配等高级功能的API使用方法,以及工作空间配额管理和审计日志相关的API说明,为多租户场景下的API使用提供指导。 + +## 项目结构 +DataVines是一个数据质量平台,其工作空间管理功能主要集中在`datavines-server`模块中。该模块提供了RESTful API接口,用于管理用户的工作空间。工作空间是用户组织和管理数据质量任务的逻辑容器,支持多用户协作和权限控制。 + +```mermaid +graph TD +subgraph "前端" +UI[用户界面] +end +subgraph "后端" +API[API服务器] +Service[工作空间服务] +Mapper[工作空间映射器] +DB[(数据库)] +end +UI --> API +API --> Service +Service --> Mapper +Mapper --> DB +``` + +**图表来源** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java#L37) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java#L32) +- [WorkSpaceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/WorkSpaceMapper.java#L24) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L166-L177) + +**章节来源** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java#L1-L89) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L200) + +## 核心组件 +工作空间管理的核心组件包括控制器(Controller)、服务(Service)、数据访问对象(Mapper)和实体(Entity)。这些组件共同实现了工作空间的创建、更新、删除、查询以及用户管理功能。 + +**章节来源** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java#L1-L89) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java#L1-L49) +- [WorkSpaceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/WorkSpaceMapper.java#L1-L25) + +## 架构概述 +工作空间管理的架构遵循典型的分层设计模式,包括表现层(Controller)、业务逻辑层(Service)和数据访问层(Mapper)。这种分层架构有助于实现关注点分离,提高代码的可维护性和可测试性。 + +```mermaid +classDiagram +class WorkSpaceController { ++createWorkSpace(WorkSpaceCreate) Object ++updateWorkSpace(WorkSpaceUpdate) Object ++deleteWorkSpace(id) Object ++listByUserId() Object ++inviteUserIntoWorkspace(InviteUserIntoWorkspace) Object ++removeUser(RemoveUserOutWorkspace) Object ++listUserByWorkspaceId(workspaceId, pageNumber, pageSize) Object +} +class WorkSpaceService { ++insert(WorkSpaceCreate) long ++update(WorkSpaceUpdate) int ++getById(id) WorkSpace ++listByUserId() WorkSpaceVO[] ++deleteById(id) int ++inviteUserIntoWorkspace(InviteUserIntoWorkspace) long ++removeUser(RemoveUserOutWorkspace) boolean ++listUserByWorkspaceId(workspaceId, pageNumber, pageSize) IPage~UserVO~ +} +class WorkSpaceMapper { ++BaseMapper~WorkSpace~ +} +class WorkSpace { ++id : Long ++name : String ++createBy : Long ++createTime : LocalDateTime ++updateBy : Long ++updateTime : LocalDateTime +} +WorkSpaceController --> WorkSpaceService : "调用" +WorkSpaceService --> WorkSpaceMapper : "调用" +WorkSpaceMapper --> WorkSpace : "映射" +``` + +**图表来源** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java#L39-L88) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java#L32-L49) +- [WorkSpaceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/WorkSpaceMapper.java#L24) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) + +## 详细组件分析 +### 工作空间控制器分析 +工作空间控制器(WorkSpaceController)是RESTful API的入口点,负责处理来自前端的HTTP请求。它使用Spring MVC框架的注解来定义API端点,并通过调用工作空间服务(WorkSpaceService)来执行具体的业务逻辑。 + +#### 对象关系图 +```mermaid +classDiagram +WorkSpaceController <|-- WorkSpaceService : "依赖" +WorkSpaceService <|-- WorkSpaceMapper : "依赖" +WorkSpaceMapper <|-- WorkSpace : "映射" +``` + +**图表来源** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java#L42) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java#L41) +- [WorkSpaceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/WorkSpaceMapper.java#L24) + +#### API调用流程 +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "WorkSpaceController" +participant Service as "WorkSpaceService" +participant Mapper as "WorkSpaceMapper" +participant DB as "数据库" +Client->>Controller : POST /api/v1/workspace +Controller->>Service : insert(WorkSpaceCreate) +Service->>Mapper : insert(WorkSpace) +Mapper->>DB : INSERT INTO dv_workspace +DB-->>Mapper : 返回插入ID +Mapper-->>Service : 返回插入结果 +Service-->>Controller : 返回工作空间ID +Controller-->>Client : 返回创建结果 +Client->>Controller : GET /api/v1/workspace/list +Controller->>Service : listByUserId() +Service->>Mapper : selectList(QueryWrapper) +Mapper->>DB : SELECT * FROM dv_workspace WHERE user关联 +DB-->>Mapper : 返回工作空间列表 +Mapper-->>Service : 返回VO列表 +Service-->>Controller : 返回工作空间VO列表 +Controller-->>Client : 返回工作空间列表 +``` + +**图表来源** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java#L45-L66) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java#L40) +- [WorkSpaceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/WorkSpaceMapper.java#L24) + +**章节来源** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java#L1-L89) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java#L1-L49) + +### 工作空间数据结构分析 +工作空间的数据结构包括输入DTO(Data Transfer Object)、输出VO(Value Object)和数据库实体。这些数据结构定义了工作空间的属性和行为。 + +#### 数据结构定义 +```mermaid +classDiagram +class WorkSpaceCreate { ++name : String +} +class WorkSpaceUpdate { ++id : Long ++name : String +} +class WorkSpaceVO { ++id : Long ++name : String ++createBy : Long ++createTime : LocalDateTime ++updateBy : Long ++updateTime : LocalDateTime +} +class WorkSpace { ++id : Long ++name : String ++createBy : Long ++createTime : LocalDateTime ++updateBy : Long ++updateTime : LocalDateTime +} +WorkSpaceCreate <|-- WorkSpaceUpdate : "继承" +WorkSpace --> WorkSpaceVO : "转换" +``` + +**图表来源** +- [WorkSpaceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceCreate.java#L27-L30) +- [WorkSpaceUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceUpdate.java#L27-L31) +- [WorkSpaceVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/WorkSpaceVO.java#L30-L44) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) + +**章节来源** +- [WorkSpaceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceCreate.java#L1-L31) +- [WorkSpaceUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceUpdate.java#L1-L32) +- [WorkSpaceVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/WorkSpaceVO.java#L1-L45) + +## 依赖分析 +工作空间管理功能依赖于多个组件和服务,包括用户服务(UserService)、用户工作空间服务(UserWorkSpaceService)和数据库访问层。这些依赖关系通过Spring的依赖注入机制进行管理。 + +```mermaid +graph TD +WorkSpaceController --> WorkSpaceService +WorkSpaceService --> WorkSpaceMapper +WorkSpaceService --> UserService +WorkSpaceService --> UserWorkSpaceService +WorkSpaceMapper --> WorkSpace +UserWorkSpaceService --> UserWorkSpace +``` + +**图表来源** +- [WorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/WorkSpaceServiceImpl.java#L53-L55) +- [UserWorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/UserWorkSpaceService.java#L28) +- [UserWorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserWorkSpaceServiceImpl.java#L27) + +**章节来源** +- [WorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/WorkSpaceServiceImpl.java#L1-L55) +- [UserWorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/UserWorkSpaceService.java#L1-L33) + +## 性能考虑 +工作空间管理功能在设计时考虑了性能因素,包括使用MyBatis-Plus的分页查询、数据库索引优化和缓存机制。这些优化措施有助于提高API的响应速度和系统的整体性能。 + +## 故障排除指南 +在使用工作空间API时,可能会遇到一些常见问题,如权限不足、参数验证失败等。建议检查请求参数是否符合要求,确保用户具有相应的权限,并查看服务器日志以获取更多错误信息。 + +**章节来源** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java#L46-L77) +- [WorkSpaceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceCreate.java#L28-L30) + +## 结论 +本文档详细介绍了DataVines平台中工作空间管理的RESTful API,包括其架构、组件、数据结构和使用方法。通过遵循本文档的指导,开发者可以有效地集成和使用工作空间管理功能,为用户提供高效的数据质量管理体验。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\346\225\260\346\215\256\346\272\220API.md" "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\346\225\260\346\215\256\346\272\220API.md" new file mode 100644 index 00000000..39e5171e --- /dev/null +++ "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\346\225\260\346\215\256\346\272\220API.md" @@ -0,0 +1,542 @@ +# 数据源API + + +**本文档引用的文件** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java) +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java) +- [DataSourceUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceUpdate.java) +- [TestConnectionRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java) +- [ConnectorRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorRequestParam.java) +- [ConnectorResponse.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java) +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java) +- [DataSourceVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/DataSourceVO.java) +- [ConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java) +- [JdbcConfigBuilder.java](file://datavines-connector/connector-plugins/connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java) +- [OracleParameterConverter.java](file://datavines-connector/connector-plugins/connector-oracle/src/main/java/io/datavines/connector/plugin/OracleParameterConverter.java) +- [DataVinesServerException.java](file://datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java) + + +## 更新摘要 +**变更内容** +- 更新了数据源连接测试API的响应格式,从简单布尔值改为结构化的ResultMap响应 +- 新增了ResultMap通用响应封装类的详细说明 +- 更新了连接测试API的请求和响应示例 +- 完善了错误处理机制的说明 + +## 目录 +1. [简介](#简介) +2. [API端点](#api端点) +3. [数据源配置JSON结构](#数据源配置json结构) +4. [请求和响应示例](#请求和响应示例) +5. [连接测试API](#连接测试api) +6. [错误处理机制](#错误处理机制) +7. [最佳实践和安全建议](#最佳实践和安全建议) + +## 简介 + +数据源API提供了管理数据源的完整功能,包括创建、更新、删除和查询数据源。该API支持多种数据库类型,如MySQL、PostgreSQL、Oracle等,并提供了测试连接、执行脚本和获取元数据的功能。API基于RESTful设计原则,使用JSON格式进行数据交换。 + +**数据源API的主要功能包括:** +- 创建新的数据源配置 +- 更新现有数据源配置 +- 删除数据源 +- 查询数据源列表和分页信息 +- 测试数据源连接 +- 获取数据库、表和列的元数据 +- 执行SQL脚本 +- 获取特定类型数据源的配置JSON模板 + +**Section sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L44-L167) + +## API端点 + +### 创建数据源 +创建一个新的数据源配置。 + +**HTTP方法**: POST +**URL路径**: `/api/datasource` +**内容类型**: `application/json` + +**请求体结构**: +- `workspaceId`: 工作空间ID (long, 必填) +- `name`: 数据源名称 (string, 必填) +- `type`: 数据源类型 (string, 必填) +- `param`: 数据源连接参数 (string, 必填, JSON格式) + +**响应格式**: 返回创建的数据源ID + +### 更新数据源 +更新现有数据源配置。 + +**HTTP方法**: PUT +**URL路径**: `/api/datasource` +**内容类型**: `application/json` + +**请求体结构**: +- `id`: 数据源ID (long, 必填) +- `workspaceId`: 工作空间ID (long, 必填) +- `name`: 数据源名称 (string, 必填) +- `type`: 数据源类型 (string, 必填) +- `param`: 数据源连接参数 (string, 必填, JSON格式) + +**响应格式**: 返回更新结果状态 + +### 删除数据源 +删除指定ID的数据源。 + +**HTTP方法**: DELETE +**URL路径**: `/api/datasource/{id}` + +**响应格式**: 返回删除结果状态 + +### 查询数据源分页列表 +获取数据源的分页列表。 + +**HTTP方法**: GET +**URL路径**: `/api/datasource/page` + +**查询参数**: +- `searchVal`: 搜索关键字 (可选) +- `workSpaceId`: 工作空间ID (必填) +- `pageNumber`: 页码 (必填) +- `pageSize`: 每页大小 (必填) + +**响应格式**: 返回分页的数据源列表 + +### 获取数据库列表 +获取指定数据源的数据库列表。 + +**HTTP方法**: GET +**URL路径**: `/api/datasource/{id}/databases` + +**响应格式**: 返回数据库列表 + +### 获取表列表 +获取指定数据源和数据库的表列表。 + +**HTTP方法**: GET +**URL路径**: `/api/datasource/{id}/{database}/tables` + +**响应格式**: 返回表列表 + +### 获取列列表 +获取指定数据源、数据库和表的列列表。 + +**HTTP方法**: GET +**URL路径**: `/api/datasource/{id}/{database}/{table}/columns` + +**响应格式**: 返回列列表 + +### 执行SQL脚本 +在指定数据源上执行SQL脚本。 + +**HTTP方法**: POST +**URL路径**: `/api/datasource/execute` +**内容类型**: `application/json` + +**请求体结构**: +- `dataSourceId`: 数据源ID +- `script`: 要执行的SQL脚本 + +**响应格式**: 返回执行结果 + +### 获取配置JSON模板 +获取指定类型数据源的配置JSON模板。 + +**HTTP方法**: GET +**URL路径**: `/api/datasource/config/{type}` + +**响应格式**: 返回配置JSON模板 + +### 获取连接器类型列表 +获取所有可用的连接器类型。 + +**HTTP方法**: GET +**URL路径**: `/api/datasource/type/list` + +**响应格式**: 返回连接器类型列表 + +**Section sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L56-L167) + +## 数据源配置JSON结构 + +数据源配置以JSON格式存储,包含连接特定数据库所需的所有参数。不同数据库类型的配置结构有所不同,但都包含基本的连接信息。 + +### 通用配置参数 +所有数据源类型都支持以下通用参数: +- `type`: 数据源类型标识 +- `host`: 数据库主机地址 +- `port`: 数据库端口 +- `user`: 用户名 +- `password`: 密码 +- `database`: 数据库名称 +- `schema`: 模式名称 +- `properties`: 连接属性(以key=value&key2=value2格式) + +### MySQL配置 +```json +{ + "type": "mysql", + "host": "localhost", + "port": "3306", + "user": "root", + "password": "password", + "database": "test", + "properties": "useSSL=false&serverTimezone=UTC" +} +``` + +### PostgreSQL配置 +```json +{ + "type": "postgresql", + "host": "localhost", + "port": "5432", + "user": "postgres", + "password": "password", + "database": "test", + "schema": "public", + "properties": "sslmode=disable" +} +``` + +### Oracle配置 +Oracle数据库使用SID或服务名进行连接: + +**使用SID连接:** +```json +{ + "type": "oracle", + "host": "localhost", + "port": "1521", + "user": "system", + "password": "password", + "sid": "ORCL", + "properties": "oracle.net.CONNECT_TIMEOUT=10000" +} +``` + +**使用服务名连接:** +```json +{ + "type": "oracle", + "host": "localhost", + "port": "1521", + "user": "system", + "password": "password", + "serviceName": "ORCLPDB1", + "properties": "oracle.net.CONNECT_TIMEOUT=10000" +} +``` + +### SQL Server配置 +```json +{ + "type": "sqlserver", + "host": "localhost", + "port": "1433", + "user": "sa", + "password": "password", + "database": "test", + "properties": "encrypt=false;trustServerCertificate=true" +} +``` + +### JDBC通用配置 +对于支持JDBC的数据库,可以使用通用JDBC配置: +```json +{ + "type": "jdbc", + "url": "jdbc:your_database_url", + "driverName": "com.your.driver.Class", + "user": "username", + "password": "password", + "properties": "property1=value1&property2=value2" +} +``` + +**Section sources** +- [ConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java#L32-L51) +- [JdbcConfigBuilder.java](file://datavines-connector/connector-plugins/connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java#L36-L72) +- [OracleParameterConverter.java](file://datavines-connector/connector-plugins/connector-oracle/src/main/java/io/datavines/connector/plugin/OracleParameterConverter.java#L25-L44) + +## 请求和响应示例 + +### 创建数据源请求示例 +```json +{ + "workspaceId": 1, + "name": "MySQL Production", + "type": "mysql", + "param": "{\"host\":\"192.168.1.100\",\"port\":\"3306\",\"user\":\"appuser\",\"password\":\"app123\",\"database\":\"production\",\"properties\":\"useSSL=false\"}" +} +``` + +### 创建数据源成功响应示例 +```json +{ + "success": true, + "msg": "操作成功", + "data": 123 +} +``` + +### 获取数据源分页列表请求示例 +``` +GET /api/datasource/page?searchVal=mysql&workSpaceId=1&pageNumber=1&pageSize=10 +``` + +### 获取数据源分页列表成功响应示例 +```json +{ + "success": true, + "msg": "操作成功", + "data": { + "records": [ + { + "id": 123, + "uuid": "a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8", + "name": "MySQL Production", + "type": "mysql", + "updater": "admin", + "updateTime": "2023-05-15 10:30:00" + } + ], + "total": 1, + "size": 10, + "current": 1, + "pages": 1 + } +} +``` + +### 获取数据库列表响应示例 +```json +{ + "success": true, + "msg": "操作成功", + "data": [ + { + "uuid": "d1e2f3g4-h5i6-7890-j1k2-l3m4n5o6p7q8", + "name": "production", + "type": "database", + "parentId": "a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8", + "metadata": {} + }, + { + "uuid": "r9s8t7u6-v5w4-3210-x9y8-z7a6b5c4d3e2", + "name": "staging", + "type": "database", + "parentId": "a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8", + "metadata": {} + } + ] +} +``` + +### 执行SQL脚本请求示例 +```json +{ + "dataSourceId": 123, + "script": "SELECT COUNT(*) FROM users WHERE created_date > '2023-01-01'" +} +``` + +### 执行SQL脚本成功响应示例 +```json +{ + "success": true, + "msg": "操作成功", + "data": { + "columns": [ + { + "name": "COUNT(*)", + "type": "BIGINT" + } + ], + "data": [ + [12345] + ] + } +} +``` + +**Section sources** +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java#L26-L39) +- [DataSourceVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/DataSourceVO.java#L25-L42) + +## 连接测试API + +连接测试API用于验证数据源配置是否正确,能够成功连接到目标数据库。 + +### API端点 +**HTTP方法**: POST +**URL路径**: `/api/datasource/test` +**内容类型**: `application/json` + +### 请求参数 +请求体为JSON格式,包含以下字段: +- `type`: 数据源类型 +- `dataSourceParam`: 数据源连接参数(与创建数据源时的param字段相同) + +### 请求示例 +```json +{ + "type": "mysql", + "dataSourceParam": "{\"host\":\"localhost\",\"port\":\"3306\",\"user\":\"root\",\"password\":\"password\",\"database\":\"test\"}" +} +``` + +### 响应格式 +**更新**:连接测试API现在返回结构化的ResultMap响应,包含完整的状态信息和错误详情。 + +成功响应: +```json +{ + "code": 200, + "msg": "Success", + "data": true +} +``` + +失败响应: +```json +{ + "code": 400, + "msg": "无法连接到数据库: Connection refused", + "data": false +} +``` + +### 实现原理 +连接测试API通过以下步骤验证连接: +1. 根据`type`参数获取对应的连接器工厂 +2. 使用连接器工厂创建连接器实例 +3. 调用连接器的`testConnect`方法进行连接测试 +4. 将连接器返回的ConnectorResponse转换为ResultMap响应格式 +5. 成功时返回包含`true`的data字段,失败时返回包含`false`的data字段 + +连接测试会实际建立数据库连接并执行简单的查询(如`SELECT 1`)来验证连接的有效性。 + +### ResultMap响应格式详解 +ResultMap是系统通用的响应封装类,提供标准化的响应格式: + +- `code`: HTTP状态码(200表示成功,400表示失败) +- `msg`: 响应消息描述 +- `data`: 实际响应数据(布尔值表示连接成功与否) + +**Section sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L59-L86) +- [TestConnectionRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java#L22-L25) +- [ConnectorRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorRequestParam.java#L22-L27) +- [ConnectorResponse.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java#L22-L52) +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java#L29-L128) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L75-L78) + +## 错误处理机制 + +数据源API实现了完善的错误处理机制,确保客户端能够获得清晰的错误信息。 + +### 常见错误代码 +| 错误代码 | 错误消息 | 说明 | +|---------|--------|------| +| 200 | Success | 操作成功 | +| 400 | 失败 | 操作失败 | +| 401 | 未授权访问 | 用户未登录或令牌无效 | +| 403 | 禁止访问 | 用户没有权限执行该操作 | +| 404 | 资源未找到 | 请求的资源不存在 | +| 409 | 冲突 | 请求与现有资源状态冲突 | +| 500 | 服务器内部错误 | 服务器处理请求时发生未知错误 | +| 503 | 服务不可用 | 服务暂时不可用 | + +### 错误响应格式 +所有错误响应都遵循统一的ResultMap格式: +```json +{ + "code": 400, + "msg": "错误描述信息", + "data": null +} +``` + +### 具体错误场景 +#### 创建数据源时的错误 +- **参数缺失**: 如果`workspaceId`、`name`、`type`或`param`为空,返回400错误 +- **工作空间不存在**: 如果指定的`workspaceId`不存在,返回404错误 +- **数据源名称重复**: 如果在同一工作空间中创建同名数据源,返回409错误 + +#### 更新数据源时的错误 +- **数据源不存在**: 如果要更新的`id`对应的数据源不存在,返回404错误 +- **参数无效**: 如果更新的参数不符合要求,返回400错误 + +#### 删除数据源时的错误 +- **数据源不存在**: 如果要删除的`id`对应的数据源不存在,返回404错误 +- **数据源正在使用**: 如果数据源被作业或其他资源引用,返回409错误 + +#### 连接测试时的错误 +- **连接失败**: 如果无法连接到数据库,返回400错误,消息中包含具体的连接错误信息 +- **认证失败**: 如果用户名或密码错误,返回400错误 +- **连接器响应为空**: 如果连接器返回null,返回400错误 + +### 异常处理实现 +后端使用`DataVinesServerException`类来处理所有业务异常。该异常类继承自`DataVinesException`,并包含状态码和错误消息。 + +```java +public class DataVinesServerException extends DataVinesException { + private Status status; + + public DataVinesServerException(Status status) { + super(status.getMsg()); + this.status = status; + } + + public DataVinesServerException(Status status, Object... statusParams) { + super(CollectionUtils.isEmpty(Arrays.asList(statusParams)) ? + status.getMsg() : MessageFormat.format(status.getMsg(), statusParams)); + this.status = status; + } + + public Status getStatus() { + return status; + } +} +``` + +**Section sources** +- [DataVinesServerException.java](file://datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java#L26-L64) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L150-L197) + +## 最佳实践和安全建议 + +### 安全最佳实践 +1. **敏感信息加密**: 所有数据源配置中的密码等敏感信息都会使用AES加密后存储在数据库中 +2. **最小权限原则**: 为数据源配置的数据库用户应仅具有执行必要操作的最小权限 +3. **定期轮换凭证**: 定期更新数据库用户的密码,并相应更新数据源配置 +4. **网络隔离**: 将数据库部署在受保护的网络区域,仅允许应用服务器访问 + +### 性能优化建议 +1. **连接池配置**: 对于频繁访问的数据源,建议配置适当的连接池大小 +2. **索引优化**: 确保在经常查询的字段上创建适当的索引 +3. **查询优化**: 避免在生产环境中执行全表扫描等低效查询 +4. **缓存策略**: 对于不经常变化的元数据,可以考虑使用缓存 + +### 使用建议 +1. **命名规范**: 使用有意义的名称来标识数据源,便于管理和识别 +2. **分类管理**: 根据环境(开发、测试、生产)或业务领域对数据源进行分类管理 +3. **文档记录**: 记录每个数据源的用途、负责人和相关业务信息 +4. **监控告警**: 设置数据源连接状态的监控和告警,及时发现连接问题 + +### 开发者建议 +1. **错误处理**: 在调用API时,妥善处理各种可能的错误情况 +2. **重试机制**: 对于临时性错误(如网络问题),实现适当的重试机制 +3. **资源清理**: 及时清理不再使用的数据源配置,避免资源浪费 +4. **版本控制**: 对重要的数据源配置变更进行记录和版本控制 + +**Section sources** +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L113-L116) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L184-L189) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\347\224\250\346\210\267API.md" "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\347\224\250\346\210\267API.md" new file mode 100644 index 00000000..c3b89005 --- /dev/null +++ "b/.qoder/repowiki/zh/content/API\345\217\202\350\200\203/\347\224\250\346\210\267API.md" @@ -0,0 +1,264 @@ +# 用户API + + +**本文档引用的文件** +- [LoginController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\LoginController.java) +- [UserController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\UserController.java) +- [UserService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\UserService.java) +- [UserServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\UserServiceImpl.java) +- [User.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\User.java) +- [UserLogin.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserLogin.java) +- [UserRegister.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserRegister.java) +- [UserResetPassword.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserResetPassword.java) +- [UserUpdate.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserUpdate.java) +- [TokenManager.java](file://datavines-core\src\main\java\io\datavines\core\utils\TokenManager.java) +- [AuthenticationInterceptor.java](file://datavines-server\src\main\java\io\datavines\server\api\inteceptor\AuthenticationInterceptor.java) +- [AuthIgnore.java](file://datavines-server\src\main\java\io\datavines\server\api\annotation\AuthIgnore.java) +- [CheckTokenExist.java](file://datavines-server\src\main\java\io\datavines\server\api\annotation\CheckTokenExist.java) +- [LoginUser.java](file://datavines-server\src\main\java\io\datavines\server\api\annotation\LoginUser.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档全面记录了DataVines平台中与用户账户管理相关的所有RESTful接口。文档详细描述了用户注册、登录、登出、密码重置、个人信息更新等API端点,涵盖了认证机制、权限控制模型、安全最佳实践以及用户状态管理等方面的内容。 + +## 项目结构 +DataVines平台的用户管理功能主要集中在`datavines-server`模块中,相关代码位于`src/main/java/io/datavines/server/api`包下。用户相关的控制器、服务、实体和数据传输对象被组织在清晰的目录结构中,便于维护和扩展。 + +```mermaid +graph TB +subgraph "API层" +LoginController["LoginController
- 登录/注册"] +UserController["UserController
- 用户信息管理"] +end +subgraph "服务层" +UserService["UserService
- 用户业务逻辑"] +end +subgraph "数据层" +User["User
- 用户实体"] +UserMapper["UserMapper
- 数据访问"] +end +LoginController --> UserService +UserController --> UserService +UserService --> UserMapper +UserMapper --> User +``` + +**图表来源** +- [LoginController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\LoginController.java#L1-L77) +- [UserController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\UserController.java#L1-L56) +- [UserService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\UserService.java#L1-L38) +- [User.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\User.java#L1-L62) + +**章节来源** +- [LoginController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\LoginController.java#L1-L77) +- [UserController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\UserController.java#L1-L56) + +## 核心组件 +用户管理功能的核心组件包括用户控制器、用户服务、用户实体和认证拦截器。这些组件协同工作,实现了完整的用户生命周期管理功能。 + +**章节来源** +- [UserService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\UserService.java#L1-L38) +- [UserServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\UserServiceImpl.java#L1-L161) + +## 架构概述 +用户API采用典型的分层架构,包括表现层、业务逻辑层和数据访问层。认证机制基于JWT(JSON Web Token),通过拦截器实现统一的权限验证。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "控制器" +participant Service as "服务层" +participant TokenManager as "令牌管理器" +participant DB as "数据库" +Client->>Controller : POST /api/login +Controller->>Service : 调用login方法 +Service->>DB : 查询用户信息 +DB-->>Service : 返回用户数据 +Service->>TokenManager : 生成JWT令牌 +TokenManager-->>Service : 返回令牌 +Service-->>Controller : 返回登录结果 +Controller-->>Client : 返回包含令牌的响应 +Client->>Controller : 带令牌的请求 +Controller->>AuthenticationInterceptor : 拦截请求 +AuthenticationInterceptor->>TokenManager : 验证令牌 +TokenManager-->>AuthenticationInterceptor : 返回验证结果 +AuthenticationInterceptor->>Controller : 继续处理 +``` + +**图表来源** +- [LoginController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\LoginController.java#L51-L58) +- [TokenManager.java](file://datavines-core\src\main\java\io\datavines\core\utils\TokenManager.java#L51-L57) +- [AuthenticationInterceptor.java](file://datavines-server\src\main\java\io\datavines\server\api\inteceptor\AuthenticationInterceptor.java#L54-L104) + +## 详细组件分析 + +### 用户认证分析 +用户认证组件负责处理用户的登录、注册和令牌管理。通过JWT实现无状态的认证机制,确保系统的可扩展性。 + +#### 认证类图 +```mermaid +classDiagram +class LoginController { ++login(UserLogin) Object ++register(UserRegister) Object +} +class UserController { ++update(UserLogin) Object ++resetPassword(UserResetPassword) Object +} +class UserService { ++login(UserLogin) UserLoginResult ++register(UserRegister) UserBaseInfo ++resetPassword(UserResetPassword) Boolean +} +class TokenManager { ++generateToken(username, password) String ++validateToken(token, username, password) Boolean ++getUsername(token) String ++getPassword(token) String +} +class AuthenticationInterceptor { ++preHandle(request, response, handler) boolean +} +LoginController --> UserService : "调用" +UserController --> UserService : "调用" +UserService --> TokenManager : "使用" +AuthenticationInterceptor --> TokenManager : "验证" +AuthenticationInterceptor --> UserService : "查询用户" +``` + +**图表来源** +- [LoginController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\LoginController.java#L1-L77) +- [UserController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\UserController.java#L1-L56) +- [UserService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\UserService.java#L1-L38) +- [TokenManager.java](file://datavines-core\src\main\java\io\datavines\core\utils\TokenManager.java#L1-L197) +- [AuthenticationInterceptor.java](file://datavines-server\src\main\java\io\datavines\server\api\inteceptor\AuthenticationInterceptor.java#L1-L116) + +**章节来源** +- [LoginController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\LoginController.java#L1-L77) +- [UserController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\UserController.java#L1-L56) +- [UserService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\UserService.java#L1-L38) + +### 用户实体分析 +用户实体定义了系统中用户的基本属性和数据结构,是用户管理功能的基础。 + +#### 用户实体类图 +```mermaid +classDiagram +class User { ++id : Long ++username : String ++password : String ++email : String ++phone : Long ++admin : Boolean ++createTime : LocalDateTime ++updateTime : LocalDateTime +} +class UserRegister { ++username : String ++email : String ++password : String ++verificationCode : String ++verificationCodeJwt : String ++phone : String +} +class UserLogin { ++username : String ++password : String +} +class UserResetPassword { ++id : Long ++oldPassword : String ++newPassword : String ++newPasswordConfirm : String +} +class UserUpdate { ++id : Long ++username : String ++email : String ++phone : String +} +class UserLoginResult { ++id : Long ++username : String ++email : String ++phone : Long ++admin : Boolean ++createTime : LocalDateTime ++updateTime : LocalDateTime +} +class UserBaseInfo { ++id : Long ++username : String ++email : String ++phone : Long ++admin : Boolean ++createTime : LocalDateTime ++updateTime : LocalDateTime +} +``` + +**图表来源** +- [User.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\User.java#L1-L62) +- [UserRegister.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserRegister.java#L1-L57) +- [UserLogin.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserLogin.java#L1-L37) +- [UserResetPassword.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserResetPassword.java#L1-L37) +- [UserUpdate.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserUpdate.java#L1-L37) +- [UserLoginResult.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\vo\UserLoginResult.java#L1-L37) +- [UserBaseInfo.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\vo\UserBaseInfo.java#L1-L37) + +**章节来源** +- [User.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\User.java#L1-L62) +- [UserRegister.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserRegister.java#L1-L57) +- [UserLogin.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\user\UserLogin.java#L1-L37) + +## 依赖分析 +用户管理模块依赖于多个核心组件,包括JWT令牌管理、数据库访问和全局异常处理。这些依赖关系确保了功能的完整性和系统的稳定性。 + +```mermaid +graph TD +UserController --> UserService +LoginController --> UserService +UserService --> UserMapper +UserService --> TokenManager +AuthenticationInterceptor --> TokenManager +AuthenticationInterceptor --> UserService +UserMapper --> User +``` + +**图表来源** +- [UserController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\UserController.java#L1-L56) +- [LoginController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\LoginController.java#L1-L77) +- [UserService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\UserService.java#L1-L38) +- [TokenManager.java](file://datavines-core\src\main\java\io\datavines\core\utils\TokenManager.java#L1-L197) +- [AuthenticationInterceptor.java](file://datavines-server\src\main\java\io\datavines\server\api\inteceptor\AuthenticationInterceptor.java#L1-L116) + +**章节来源** +- [UserService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\UserService.java#L1-L38) +- [TokenManager.java](file://datavines-core\src\main\java\io\datavines\core\utils\TokenManager.java#L1-L197) +- [AuthenticationInterceptor.java](file://datavines-server\src\main\java\io\datavines\server\api\inteceptor\AuthenticationInterceptor.java#L1-L116) + +## 性能考虑 +用户认证系统采用了JWT无状态认证机制,避免了服务器端会话存储,提高了系统的可扩展性。密码使用BCrypt算法进行哈希存储,确保了安全性的同时也考虑了计算性能。 + +## 故障排除指南 +当用户遇到登录问题时,应首先检查用户名和密码是否正确。如果忘记密码,可以使用密码重置功能。系统会验证旧密码的正确性,然后允许设置新密码。 + +**章节来源** +- [UserServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\UserServiceImpl.java#L133-L153) +- [TokenManager.java](file://datavines-core\src\main\java\io\datavines\core\utils\TokenManager.java#L163-L167) + +## 结论 +DataVines平台的用户API提供了完整的用户账户管理功能,包括注册、登录、密码重置等核心操作。通过JWT认证机制和分层架构设计,系统既保证了安全性又具备良好的可扩展性。建议在使用时遵循安全最佳实践,定期更新密码并妥善保管认证令牌。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227.md" "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227.md" new file mode 100644 index 00000000..3ffb4f82 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227.md" @@ -0,0 +1,277 @@ +# 开发者指南 + + +**本文档中引用的文件** +- [pom.xml](file://pom.xml) +- [README.md](file://README.md) +- [mvnw](file://mvnw) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [package.json](file://datavines-ui/package.json) +- [checkStyle.xml](file://tools/checkstyle/checkStyle.xml) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) +- [datavines-submit.sh](file://bin/datavines-submit.sh) +- [.eslintrc.js](file://datavines-ui/.eslintrc.js) +- [DataVinesArchitecture](docs/img/architecture.jpg) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [开发环境搭建](#开发环境搭建) +4. [构建系统与依赖管理](#构建系统与依赖管理) +5. [代码风格与规范](#代码风格与规范) +6. [单元测试与集成测试](#单元测试与集成测试) +7. [代码提交流程](#代码提交流程) +8. [代码审查标准](#代码审查标准) +9. [调试技巧与性能分析](#调试技巧与性能分析) +10. [分支策略与发布流程](#分支策略与发布流程) +11. [新贡献者入门指导](#新贡献者入门指导) + +## 简介 +DataVines 是一个易于使用的数据质量服务平台,支持多种指标。该项目采用插件化设计,具有良好的扩展性,支持多种数据源、检查规则、作业执行引擎、告警通道、错误数据存储和注册中心。平台提供网页配置检查作业、运行作业、查看作业执行日志、查看错误数据和检查结果的功能,同时也支持在线生成作业运行脚本,通过 `datavines-submit.sh` 提交作业,可与调度系统结合使用。 + +**Section sources** +- [README.md](file://README.md#L19-L136) + +## 项目结构 +DataVines 项目采用 Maven 多模块结构,主要模块包括: +- `datavines-common`: 公共模块,包含配置、数据源、实体、枚举、异常、日志、参数、工具类等 +- `datavines-engine`: 引擎模块,包含引擎API、公共工具、配置、核心、执行器和插件 +- `datavines-cli`: 命令行接口模块 +- `datavines-connector`: 连接器模块,包含API和各种数据源插件 +- `datavines-ui`: 用户界面模块,基于 React 和 Ant Design 构建 +- `datavines-server`: 服务器模块,基于 Spring Boot 构建 +- `datavines-metric`: 指标模块,包含API、期望值插件、指标插件和结果公式插件 +- `datavines-notification`: 通知模块,包含API、核心和各种通知插件 +- `datavines-registry`: 注册中心模块,包含API和各种注册中心插件 +- `datavines-runner`: 作业执行模块 +- `datavines-spi`: SPI 模块,包含插件加载、优先级和SPI注解 + +```mermaid +graph TD +A[DataVines] --> B[datavines-common] +A --> C[datavines-engine] +A --> D[datavines-cli] +A --> E[datavines-connector] +A --> F[datavines-ui] +A --> G[datavines-server] +A --> H[datavines-metric] +A --> I[datavines-notification] +A --> J[datavines-registry] +A --> K[datavines-runner] +A --> L[datavines-spi] +``` + +**Diagram sources ** +- [pom.xml](file://pom.xml#L30-L45) + +**Section sources** +- [pom.xml](file://pom.xml#L21-L907) + +## 开发环境搭建 +### 前置条件 +- JDK 8 +- Maven 3.6.1 或更高版本 +- Node.js (用于前端开发) +- 数据库 (MySQL 或 PostgreSQL) + +### 环境配置 +1. 克隆项目仓库 +2. 配置数据库连接信息 +3. 安装前端依赖 + +```bash +# 安装前端依赖 +cd datavines-ui +npm install +``` + +**Section sources** +- [README.md](file://README.md#L95-L97) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [package.json](file://datavines-ui/package.json#L1-L100) + +## 构建系统与依赖管理 +### Maven 构建 +DataVines 使用 Maven 作为构建工具。项目根目录下的 `pom.xml` 文件定义了所有模块的依赖关系和构建配置。 + +```bash +# 构建项目 +mvn clean package -Prelease -DskipTests +``` + +### 依赖管理 +项目使用 Maven 的 `dependencyManagement` 来统一管理依赖版本,确保所有模块使用一致的依赖版本。 + +```xml + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + +``` + +**Section sources** +- [pom.xml](file://pom.xml#L129-L701) +- [README.md](file://README.md#L31-L34) + +## 代码风格与规范 +### Java 代码规范 +项目使用 Checkstyle 进行代码风格检查,配置文件位于 `tools/checkstyle/checkStyle.xml`。主要规范包括: +- 使用 UTF-8 编码 +- 禁止使用 `System.out.println` +- 禁止使用 `@author` 注解 +- 禁止使用中文字符 +- 禁止 TODO 注释中包含用户名 +- 禁止行尾空格 +- 禁止使用 `Throwables.propagate` +- 文件长度不超过 3000 行 +- 行长度不超过 500 字符 +- 包名必须以 `io.datavines` 开头 +- 类名、方法名、变量名遵循驼峰命名法 + +### JavaScript/TypeScript 代码规范 +前端代码使用 ESLint 进行代码风格检查,配置文件位于 `datavines-ui/.eslintrc.js`。主要规范包括: +- 使用 4 空格缩进 +- 使用单引号 +- 行长度不超过 200 字符 +- 禁用 `no-console` 规则 +- 禁用 `no-use-before-define` 规则 + +**Section sources** +- [checkStyle.xml](file://tools/checkstyle/checkStyle.xml#L1-L522) +- [.eslintrc.js](file://datavines-ui/.eslintrc.js#L1-L62) + +## 单元测试与集成测试 +### 单元测试 +项目使用 JUnit 进行单元测试,测试代码位于各模块的 `src/test` 目录下。 + +```java +@Test +public void testDataVinesClient() { + // 测试代码 +} +``` + +### 集成测试 +项目使用 Spring Test 进行集成测试,测试代码位于 `datavines-server` 模块的 `src/test` 目录下。 + +```java +@SpringBootTest +class DataVinesServerApplicationTests { + @Test + void contextLoads() { + } +} +``` + +**Section sources** +- [pom.xml](file://pom.xml#L295-L300) +- [spring.version](file://pom.xml#L105) +- [DataVinesClientTest.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/test/java/io/datavines/http/clinet/DataVinesClientTest.java) +- [ZooKeeperRegistryTest.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/test/java/io/datavines/registry/plugin/ZooKeeperRegistryTest.java) + +## 代码提交流程 +1. 创建新的功能分支 +2. 在分支上进行开发 +3. 提交代码到远程仓库 +4. 创建 Pull Request +5. 等待代码审查 +6. 根据审查意见修改代码 +7. 合并到主分支 + +```bash +# 创建功能分支 +git checkout -b feature/new-feature + +# 提交代码 +git add . +git commit -m "Add new feature" +git push origin feature/new-feature +``` + +**Section sources** +- [README.md](file://README.md#L107-L115) + +## 代码审查标准 +### 代码质量 +- 代码必须通过 Checkstyle 和 ESLint 检查 +- 代码必须有适当的单元测试和集成测试 +- 代码必须有适当的注释和文档 +- 代码必须遵循项目的设计模式和架构 + +### 代码风格 +- 代码必须遵循项目的代码风格规范 +- 代码必须有适当的命名 +- 代码必须有适当的缩进和格式化 + +### 功能实现 +- 功能必须完整实现 +- 功能必须经过充分测试 +- 功能必须有适当的错误处理 + +**Section sources** +- [checkStyle.xml](file://tools/checkstyle/checkStyle.xml#L1-L522) +- [.eslintrc.js](file://datavines-ui/.eslintrc.js#L1-L62) + +## 调试技巧与性能分析 +### 调试技巧 +- 使用 IDE 的调试功能 +- 使用日志输出调试信息 +- 使用 JMX 进行远程监控和调试 + +### 性能分析 +- 使用 JProfiler 或 VisualVM 进行性能分析 +- 使用 JMX Exporter 导出性能指标 +- 使用 Prometheus 和 Grafana 进行监控 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L72-L80) +- [jmx_exporter_config.yaml](file://datavines-server/src/main/resources/jmx/jmx_exporter_config.yaml) + +## 分支策略与发布流程 +### 分支策略 +- `main` 分支:主分支,用于发布稳定版本 +- `develop` 分支:开发分支,用于集成开发中的功能 +- `feature/*` 分支:功能分支,用于开发新功能 +- `hotfix/*` 分支:热修复分支,用于修复紧急问题 + +### 发布流程 +1. 从 `develop` 分支创建发布分支 `release/*` +2. 在发布分支上进行最后的测试和修复 +3. 合并发布分支到 `main` 分支 +4. 在 `main` 分支上打标签 +5. 合并发布分支到 `develop` 分支 +6. 删除发布分支 + +**Section sources** +- [README.md](file://README.md#L107-L115) + +## 新贡献者入门指导 +### 入门步骤 +1. 阅读项目 README 文件 +2. 搭建开发环境 +3. 运行项目 +4. 阅读代码 +5. 选择一个简单的任务开始贡献 + +### 贡献方式 +- 提交 Bug 报告 +- 提交功能建议 +- 提交代码补丁 +- 改进文档 + +### 资源链接 +- [项目文档](https://datavane.github.io/datavines-website/docs/user-guide/quick-start) +- [开发环境准备](https://datavane.github.io/datavines-website/docs/development/environment-preparation) +- [贡献指南](https://github.com/datavane/datavines/blob/main/CONTRIBUTING.md) + +**Section sources** +- [README.md](file://README.md#L101-L115) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\277\253\351\200\237\345\205\245\351\227\250.md" "b/.qoder/repowiki/zh/content/\345\277\253\351\200\237\345\205\245\351\227\250.md" new file mode 100644 index 00000000..547b0194 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\277\253\351\200\237\345\205\245\351\227\250.md" @@ -0,0 +1,315 @@ +# 快速入门 + + +**本文档中引用的文件** +- [README.md](file://README.md) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) +- [datavines-submit.sh](file://bin/datavines-submit.sh) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [Dockerfile](file://deploy/docker/Dockerfile) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [.env](file://deploy/compose/.env) + + +## 目录 +1. [简介](#简介) +2. [环境准备](#环境准备) +3. [数据库初始化](#数据库初始化) +4. [服务启动](#服务启动) +5. [最小化配置示例](#最小化配置示例) +6. [端到端使用示例](#端到端使用示例) +7. [不同操作系统的注意事项](#不同操作系统的注意事项) +8. [常见问题排查](#常见问题排查) +9. [总结](#总结) + +## 简介 + +DataVines 是一个易于使用的数据质量服务平台,支持多种数据质量检查规则和执行引擎。本指南将帮助您在本地环境中快速部署和运行 DataVines,从零开始完成安装、配置、启动和验证的全过程。 + +**Section sources** +- [README.md](file://README.md#L24-L98) + +## 环境准备 + +在部署 DataVines 之前,需要确保您的系统满足以下环境依赖: + +1. **Java 运行环境**:需要 JDK 8 或更高版本 +2. **Maven**:需要 Maven 3.6.1 或更高版本用于构建项目 +3. **数据库**:支持 MySQL 或 PostgreSQL,用于存储元数据和运行信息 +4. **可选依赖**: + - 如果使用 Spark 作为执行引擎,需要确保服务器已安装 Spark + - 如果数据量较小或仅用于功能验证,可以使用 JDBC 引擎 + +构建项目: +```bash +mvn clean package -Prelease -DskipTests +``` + +构建完成后,将在 `datavines-dist/target/` 目录下生成 `datavines-x.x.x-bin.tar.gz` 安装包。 + +**Section sources** +- [README.md](file://README.md#L31-L34) +- [README.md](file://README.md#L95-L98) + +## 数据库初始化 + +DataVines 使用关系型数据库存储元数据和运行信息。以下是针对 MySQL 的数据库初始化步骤: + +1. 创建数据库: +```sql +CREATE DATABASE datavines DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +``` + +2. 执行初始化脚本: +```bash +mysql -u root -p datavines < scripts/sql/datavines-mysql.sql +``` + +该脚本将创建所有必要的表结构,包括数据源、作业、执行实例、结果存储等。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L800) + +## 服务启动 + +DataVines 提供了多种启动方式,包括直接启动、Docker 启动和提交作业。 + +### 直接启动方式 + +1. 解压安装包: +```bash +tar -zxvf datavines-x.x.x-bin.tar.gz +cd datavines-x.x.x-bin +``` + +2. 修改数据库配置: +编辑 `conf/application.yaml` 文件,根据您的数据库类型选择相应的配置。默认配置使用 PostgreSQL,如需使用 MySQL,可通过命令行参数指定: + +```bash +bin/datavines-daemon.sh start mysql +``` + +3. 启动服务: +```bash +# 启动服务(使用 MySQL 配置) +bin/datavines-daemon.sh start mysql + +# 停止服务 +bin/datavines-daemon.sh stop + +# 查看服务状态 +bin/datavines-daemon.sh status +``` + +### Docker 启动方式 + +1. 构建 Docker 镜像: +```bash +docker build -t datavines:dev -f deploy/docker/Dockerfile . +``` + +2. 启动容器: +```bash +docker-compose -f deploy/compose/docker-compose.yaml up -d +``` + +Docker 配置文件中定义了以下环境变量: +- 端口映射:5600:5600 +- 数据库连接:通过 .env 文件配置 +- 容器名称:datavines + +**Section sources** +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) + +## 最小化配置示例 + +以下是最小化配置示例,用于快速验证安装是否成功: + +1. **application.yaml 配置**(MySQL 版本): +```yaml +spring: + profiles: + active: mysql + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/datavines?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: 123456 +server: + port: 5600 +``` + +2. **验证服务是否正常运行**: +```bash +# 检查端口是否监听 +netstat -an | grep 5600 + +# 检查进程是否运行 +ps aux | grep datavines + +# 访问 Web 界面 +http://localhost:5600 +``` + +预期输出: +- 服务启动日志中显示 "Datavines server start" +- 端口 5600 处于监听状态 +- Web 界面可以正常访问 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L84-L96) + +## 端到端使用示例 + +以下是一个完整的端到端使用示例,演示如何配置数据源、创建质量检查任务并查看结果。 + +### 1. 配置数据源 + +通过 API 或 Web 界面配置 MySQL 数据源: +```json +{ + "name": "test_mysql", + "type": "mysql", + "param": { + "host": "127.0.0.1", + "port": 3306, + "username": "root", + "password": "123456", + "database": "test" + } +} +``` + +### 2. 创建质量检查任务 + +创建一个检查表行数的任务: +```bash +# 提交作业 +bin/datavines-submit.sh submit_job_mysql_storage.json +``` + +作业配置文件示例: +```json +{ + "job": { + "name": "check_table_row_count", + "type": 0, + "datasource_id": 1, + "schema_name": "test", + "table_name": "users", + "metric_type": "table_row_count", + "engine_type": "local" + } +} +``` + +### 3. 查看执行结果 + +1. 通过 Web 界面查看作业执行历史 +2. 查看作业执行日志 +3. 检查结果存储表 `dv_job_execution_result` +4. 查看质量评分报告 `dv_job_quality_report` + +**Section sources** +- [datavines-submit.sh](file://bin/datavines-submit.sh#L1-L49) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) + +## 不同操作系统的注意事项 + +### Linux/Unix 系统 + +1. 确保有足够权限执行脚本: +```bash +chmod +x bin/*.sh +``` + +2. 检查环境变量是否正确设置: +```bash +echo $JAVA_HOME +echo $PATH +``` + +### Windows 系统 + +1. 使用 Git Bash 或 WSL 运行 shell 脚本 +2. 确保行尾符正确(LF 而不是 CRLF) +3. 路径分隔符使用正斜杠 `/` +4. 可能需要修改脚本中的路径处理逻辑 + +### macOS 系统 + +1. 确保已安装 Xcode 命令行工具 +2. 可能需要调整 JVM 内存参数 +3. 注意防火墙设置,确保端口可访问 + +**Section sources** +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L45-L52) +- [datavines-submit.sh](file://bin/datavines-submit.sh#L31-L33) + +## 常见问题排查 + +### 端口冲突 + +问题:端口 5600 已被占用 +解决方案: +```bash +# 查找占用端口的进程 +lsof -i :5600 +# 或 +netstat -anp | grep 5600 + +# 终止进程或修改配置文件中的端口 +server: + port: 5601 +``` + +### 数据库连接失败 + +问题:无法连接到数据库 +检查项: +1. 数据库服务是否已启动 +2. 连接 URL、用户名、密码是否正确 +3. 数据库驱动是否匹配 +4. 网络连接是否正常 +5. 防火墙是否阻止连接 + +### 服务启动失败 + +常见错误及解决方案: +1. **Java 环境问题**:确保 JAVA_HOME 正确设置 +2. **内存不足**:调整 JVM 参数 +3. **依赖缺失**:确保所有依赖库已正确打包 +4. **权限问题**:确保有足够权限读写文件和目录 + +日志文件位置:`logs/datavines-server-.out` + +### 作业执行失败 + +检查步骤: +1. 查看作业执行日志 +2. 检查数据源连接是否正常 +3. 验证 SQL 语句是否正确 +4. 检查执行引擎配置 +5. 查看错误数据存储配置 + +**Section sources** +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L136-L152) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L69-L71) + +## 总结 + +本指南详细介绍了 DataVines 的本地部署和运行过程,包括环境准备、数据库初始化、服务启动、配置示例和常见问题排查。通过本指南,用户可以快速搭建 DataVines 环境并验证其基本功能。 + +关键要点: +- 确保 Java 和 Maven 环境正确配置 +- 根据数据库类型选择合适的配置文件 +- 使用提供的脚本简化启动和管理过程 +- 通过最小化配置快速验证安装 +- 利用端到端示例理解完整工作流程 +- 参考常见问题排查指南解决部署中的问题 + +完成部署后,用户可以通过 Web 界面或 API 进一步探索 DataVines 的各项功能,包括数据目录、数据质量检查、数据画像等。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\345\221\212\350\255\246\351\200\232\351\201\223\346\217\222\344\273\266\345\274\200\345\217\221.md" "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\345\221\212\350\255\246\351\200\232\351\201\223\346\217\222\344\273\266\345\274\200\345\217\221.md" new file mode 100644 index 00000000..f252f341 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\345\221\212\350\255\246\351\200\232\351\201\223\346\217\222\344\273\266\345\274\200\345\217\221.md" @@ -0,0 +1,524 @@ +# 告警通道插件开发 + + +**本文档中引用的文件** +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java) +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java) +- [LarkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSlasHandlerPlugin.java) +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSlasHandlerPlugin.java) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java) +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java) +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java) +- [SlaNotificationMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationMessage.java) +- [SlaNotificationResult.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationResult.java) +- [NotificationConstants.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\constants\NotificationConstants.java) +- [DingTalkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkConstants.java) +- [LarkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkConstants.java) +- [WecomBotConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotConstants.java) + + +## 目录 +1. [引言](#引言) +2. [核心接口设计](#核心接口设计) +3. [通知管理器架构](#通知管理器架构) +4. [插件实现示例](#插件实现示例) +5. [通知模板与动态内容](#通知模板与动态内容) +6. [错误处理与重试机制](#错误处理与重试机制) +7. [安全性考虑](#安全性考虑) +8. [开发指南](#开发指南) + +## 引言 +本文档详细介绍了如何为DataVines开发新的告警通知插件。通过分析现有的钉钉、邮件、飞书和企业微信插件实现,我们将深入探讨SlasHandlerPlugin接口的设计原理和实现方法。文档涵盖了从消息构建、认证处理到请求发送的完整流程,以及通知模板配置、动态内容填充、发送失败重试机制和错误日志记录等关键功能。同时,我们也会讨论凭证管理和传输加密等安全性考虑,为开发者提供全面的指导。 + +## 核心接口设计 + +告警通道插件的核心是`SlasHandlerPlugin`接口,它定义了所有通知插件必须实现的基本功能。该接口通过SPI(Service Provider Interface)机制进行扩展,允许系统动态加载和管理不同的通知通道。 + +```mermaid +classDiagram +class SlasHandlerPlugin { +<> ++notify(SlaNotificationMessage, Map~SlaSenderMessage, Set~SlaConfigMessage~~) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class SlaNotificationMessage { +-Long slaId +-String subject +-String message +} +class SlaNotificationResult { +-Boolean status +-SlaNotificationResultRecord[] records ++merge(SlaNotificationResult) SlaNotificationResult +} +class SlaNotificationResultRecord { +-Boolean status +-String message +} +class SlaSenderMessage { +-String type +-String config +} +class SlaConfigMessage { +-String config +} +SlasHandlerPlugin <|-- DingTalkSlasHandlerPlugin +SlasHandlerPlugin <|-- EmailSlasHandlerPlugin +SlasHandlerPlugin <|-- LarkSlasHandlerPlugin +SlasHandlerPlugin <|-- WecomBotSlasHandlerPlugin +SlaNotificationResult "1" --> "0..*" SlaNotificationResultRecord +``` + +**图示来源** +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java#L28-L42) +- [SlaNotificationMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationMessage.java#L28-L35) +- [SlaNotificationResult.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationResult.java#L30-L52) + +`SlasHandlerPlugin`接口包含三个核心方法: +- `notify`:执行实际的通知发送操作,接收通知消息和配置信息,返回发送结果 +- `getConfigSenderJson`:获取发送器级别的配置信息,通常包含通道的全局配置 +- `getConfigJson`:获取具体通知配置信息,定义了用户在创建告警时需要填写的参数 + +**本节来源** +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java#L28-L42) + +## 通知管理器架构 + +`NotificationManager`是告警通知系统的核心管理组件,负责协调各个通知插件的调用。它使用插件加载器动态发现和实例化所有支持的告警通道插件,并根据配置信息路由通知请求。 + +```mermaid +sequenceDiagram +participant NotificationManager +participant PluginLoader +participant SlasHandlerPlugin +participant DingTalkSender +participant EMailSender +participant LarkSender +participant WecomBotSender +NotificationManager->>PluginLoader : 初始化时获取所有支持的插件 +PluginLoader-->>NotificationManager : 返回支持的插件类型列表 +NotificationManager->>NotificationManager : 存储支持的插件类型 +NotificationManager->>NotificationManager : 验证配置的有效性 +alt 配置无效 +NotificationManager-->>调用者 : 抛出DataVinesException +else 配置有效 +loop 遍历每个发送器配置 +NotificationManager->>PluginLoader : 根据类型获取插件实例 +PluginLoader-->>NotificationManager : 返回插件实例 +NotificationManager->>SlasHandlerPlugin : 调用notify方法 +SlasHandlerPlugin->>DingTalkSender : 发送钉钉消息 +SlasHandlerPlugin->>EMailSender : 发送邮件 +SlasHandlerPlugin->>LarkSender : 发送飞书消息 +SlasHandlerPlugin->>WecomBotSender : 发送企业微信消息 +SlasHandlerPlugin-->>NotificationManager : 返回发送结果 +NotificationManager->>NotificationManager : 合并所有结果 +end +NotificationManager-->>调用者 : 返回最终的发送结果 +end +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java#L35-L69) + +`NotificationManager`的实现要点包括: +1. 在构造函数中通过`PluginLoader`获取所有支持的插件类型,存储在`supportedPlugins`集合中 +2. `notify`方法首先验证配置的有效性,确保至少有一个发送器配置 +3. 遍历配置中的每个发送器,检查其类型是否被支持 +4. 通过`PluginLoader`获取对应类型的插件实例 +5. 调用插件的`notify`方法执行实际的通知发送 +6. 将各个插件的发送结果合并,返回统一的结果 + +**本节来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java#L35-L69) + +## 插件实现示例 + +### 钉钉插件实现 + +钉钉告警插件`DingTalkSlasHandlerPlugin`实现了`SlasHandlerPlugin`接口,提供了完整的钉钉机器人消息发送功能。 + +```mermaid +classDiagram +class DingTalkSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map~SlaSenderMessage, Set~SlaConfigMessage~~) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class DingTalkSender { +-String msgType ++sendCardMsg(Set~ReceiverConfig~, String, String) SlaNotificationResultRecord +-generateMsgJson(String, String, ReceiverConfig) String +-constructUrl(String, String) String +-constructHttpPost(String, String) HttpPost +} +class ReceiverConfig { +-String webhook +-String secret +-String keyWord +-String atMobiles +-String atDingtalkIds +-Boolean isAtAll +} +class DingTalkConstants { ++DING_TALK_MSG_TYPE_TEXT ++DING_TALK_MSG_TYPE_MARKDOWN ++MSG_TYPE +} +DingTalkSlasHandlerPlugin --> DingTalkSender : 使用 +DingTalkSender --> ReceiverConfig : 使用 +DingTalkSender --> DingTalkConstants : 使用 +``` + +**图示来源** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L39-L133) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L51-L192) +- [DingTalkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkConstants.java#L19-L30) + +钉钉插件的关键实现细节: +- `notify`方法过滤出类型为"dingtalk"的发送器配置,为每个配置创建`DingTalkSender`实例 +- `getConfigJson`方法定义了钉钉通知的配置参数,包括webhook、secret、关键词、@手机号等 +- `DingTalkSender`负责构建符合钉钉API要求的JSON消息体,支持文本和Markdown格式 +- 实现了钉钉机器人安全验证机制,通过HMAC-SHA256签名确保请求的安全性 + +**本节来源** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L39-L133) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L51-L192) + +### 邮件插件实现 + +邮件告警插件`EmailSlasHandlerPlugin`提供了完整的邮件发送功能,支持SMTP认证和SSL/TLS加密。 + +```mermaid +classDiagram +class EmailSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map~SlaSenderMessage, Set~SlaConfigMessage~~) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +-getInputParam(String, String, String, int, Validate) InputParam +-getInputParamNoValidate(String, String, String, int) InputParam +} +class EMailSender { +-String mailSmtpHost +-String mailSmtpPort +-String mailSenderEmail +-String enableSmtpAuth +-String mailUser +-String mailPasswd +-String mailUseStartTLS +-String mailUseSSL +-String sslTrust ++sendMails(Set~String~, Set~String~, String, String) SlaNotificationResultRecord +-getSession() Session +-getTextTypeMessage(String) String +} +class ReceiverConfig { +-String to +-String cc +} +EmailSlasHandlerPlugin --> EMailSender : 使用 +EMailSender --> ReceiverConfig : 使用 +``` + +**图示来源** +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L43-L224) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L44-L197) + +邮件插件的关键实现细节: +- `notify`方法解析收件人和抄送人列表,支持逗号或分号分隔的多个邮箱地址 +- `getConfigSenderJson`方法定义了邮件服务器的全局配置,包括SMTP主机、端口、认证信息等 +- `getConfigJson`方法定义了具体的收件人配置 +- `EMailSender`使用Apache Commons Mail库发送邮件,支持HTML格式和附件 +- 实现了完整的SMTP会话配置,包括STARTTLS、SSL和证书信任设置 + +**本节来源** +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L43-L224) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L44-L197) + +### 飞书插件实现 + +飞书告警插件`LarkSlasHandlerPlugin`实现了飞书机器人的消息发送功能。 + +```mermaid +classDiagram +class LarkSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map~SlaSenderMessage, Set~SlaConfigMessage~~) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class LarkSender { +-String alarmTitle +-String alarmColor +-String subjectKey +-String messageKey +-String atAllKey ++sendCardMsg(Set~ReceiverConfig~, String, String) SlaNotificationResultRecord +} +class ReceiverConfig { +-String webhook +-Boolean atAll +-String groupName +} +class LarkConstants { ++MSG_TYPE ++DEFAULT_MSG_TYPE ++CARD ++LARK_API ++GROUP_HOOK_URL ++ACCESS_TOKEN_QUERY_URL ++USER_OPEN_ID_QUERY_URL ++MESSAGES_URL +} +LarkSlasHandlerPlugin --> LarkSender : 使用 +LarkSender --> ReceiverConfig : 使用 +LarkSender --> LarkConstants : 使用 +``` + +**图示来源** +- [LarkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSlasHandlerPlugin.java#L39-L132) +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java#L38-L84) +- [LarkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkConstants.java#L20-L35) + +飞书插件的关键实现细节: +- 使用飞书的交互式卡片消息格式,提供更好的视觉效果 +- 支持@所有人功能,通过`atAll`配置项控制 +- `LarkSender`直接使用HTTP工具类发送POST请求到飞书API +- 消息内容采用结构化JSON格式,包含标题、颜色和消息列表 + +**本节来源** +- [LarkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSlasHandlerPlugin.java#L39-L132) +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java#L38-L84) + +### 企业微信插件实现 + +企业微信告警插件`WecomBotSlasHandlerPlugin`实现了企业微信机器人的消息发送功能。 + +```mermaid +classDiagram +class WecomBotSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map~SlaSenderMessage, Set~SlaConfigMessage~~) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class WecomBotSender { ++sendMsg(Set~ReceiverConfig~, String, String) SlaNotificationResultRecord +-getMarkdownMessage(String, String) String +} +class ReceiverConfig { +-String webhook +} +class WecomBotRes { +-Integer errcode +-String errmsg ++success() boolean +} +class WecomBotConstants { ++MSG_TYPE ++MARKDOWN ++CONTENT ++FIRST_TITLE_START ++QUOTE_START ++END +} +WecomBotSlasHandlerPlugin --> WecomBotSender : 使用 +WecomBotSender --> ReceiverConfig : 使用 +WecomBotSender --> WecomBotRes : 使用 +WecomBotSender --> WecomBotConstants : 使用 +``` + +**图示来源** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSlasHandlerPlugin.java#L33-L97) +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L38-L95) +- [WecomBotConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotConstants.java) + +企业微信插件的关键实现细节: +- 使用Markdown消息格式,支持丰富的文本样式 +- `WecomBotSender`发送消息后会解析响应结果,通过`WecomBotRes`类判断发送是否成功 +- 实现了消息内容的格式化处理,将JSON数组转换为Markdown列表 +- 支持链接格式化,将任务执行记录转换为可点击的链接 + +**本节来源** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSlasHandlerPlugin.java#L33-L97) +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L38-L95) + +## 通知模板与动态内容 + +DataVines的告警通知系统支持灵活的消息模板和动态内容填充。通知消息由主题(subject)和内容(message)两部分组成,其中内容可以是包含多个消息项的JSON数组。 + +```mermaid +flowchart TD +Start([开始]) --> ParseMessage["解析消息内容为JSON数组"] +ParseMessage --> CheckContent{"内容是否为空?"} +CheckContent --> |是| ReturnOriginal["返回原始内容"] +CheckContent --> |否| ProcessItems["遍历每个消息项"] +ProcessItems --> CheckLink{"是否为任务执行记录?"} +CheckLink --> |是| FormatLink["格式化为可点击链接"] +CheckLink --> |否| KeepOriginal["保持原始文本"] +FormatLink --> AddToResult["添加到结果字符串"] +KeepOriginal --> AddToResult +AddToResult --> MoreItems{"还有更多项?"} +MoreItems --> |是| ProcessItems +MoreItems --> |否| WrapHTML["包装为HTML/Markdown格式"] +WrapHTML --> ReturnResult["返回格式化后的内容"] +ReturnOriginal --> ReturnResult +ReturnResult --> End([结束]) +``` + +**图示来源** +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L178-L193) +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L76-L93) + +不同通知通道对消息内容的处理方式: +- **邮件**:将JSON数组转换为HTML表格,任务执行记录转换为超链接 +- **企业微信**:将JSON数组转换为Markdown列表,任务执行记录转换为可点击链接 +- **钉钉**:支持文本和Markdown格式,可包含@功能 +- **飞书**:使用交互式卡片格式,提供结构化的消息展示 + +**本节来源** +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L178-L193) +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L76-L93) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L111-L177) +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java#L61-L66) + +## 错误处理与重试机制 + +告警通知系统实现了完善的错误处理和重试机制,确保通知的可靠送达。 + +```mermaid +flowchart TD +Start([开始发送通知]) --> CheckConfig["验证配置有效性"] +CheckConfig --> IsValid{"配置有效?"} +IsValid --> |否| ThrowException["抛出DataVinesException"] +IsValid --> |是| LoopSenders["遍历每个发送器"] +LoopSenders --> GetPlugin["获取插件实例"] +GetPlugin --> IsValidPlugin{"插件类型支持?"} +IsValidPlugin --> |否| ThrowException +IsValidPlugin --> |是| CallNotify["调用插件notify方法"] +CallNotify --> CatchError{"发生异常?"} +CatchError --> |是| RecordFailure["记录失败的接收者"] +CatchError --> |否| Continue +RecordFailure --> LogError["记录错误日志"] +Continue --> NextSender{"还有更多发送器?"} +NextSender --> |是| LoopSenders +NextSender --> |否| CheckFailures{"有失败的接收者?"} +CheckFailures --> |是| SetStatus["设置结果状态为失败"] +CheckFailures --> |否| SetSuccess["设置结果状态为成功"] +SetStatus --> ReturnResult["返回结果"] +SetSuccess --> ReturnResult +ThrowException --> ReturnResult +ReturnResult --> End([结束]) +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java#L45-L68) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L55-L89) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L137-L140) + +错误处理的关键特点: +1. **分层错误处理**:在`NotificationManager`层面验证配置有效性,在插件层面处理具体的发送错误 +2. **细粒度失败记录**:每个插件记录具体的失败接收者,提供详细的错误信息 +3. **异常捕获**:所有发送操作都包含在try-catch块中,防止单个发送失败影响整体流程 +4. **日志记录**:详细的错误日志帮助诊断问题,包括异常堆栈信息 +5. **结果合并**:将所有插件的发送结果合并,提供统一的成功/失败状态 + +**本节来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java#L45-L68) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L55-L89) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L137-L140) + +## 安全性考虑 + +告警通知系统在设计时充分考虑了安全性,特别是在凭证管理和传输加密方面。 + +### 凭证管理 + +系统通过以下方式确保凭证的安全: +- **配置隔离**:发送器级别的配置(如SMTP服务器、用户名、密码)与具体的接收者配置分离 +- **加密存储**:敏感信息如密码在存储时应进行加密处理 +- **最小权限原则**:每个通知通道使用专用的凭证,避免权限过度分配 + +### 传输加密 + +不同通知通道的传输加密机制: +- **钉钉**:支持通过secret进行HMAC-SHA256签名,确保请求的完整性和真实性 +- **邮件**:支持STARTTLS和SSL/TLS加密,保护邮件内容在传输过程中的安全 +- **飞书**:通过HTTPS协议传输,使用访问令牌进行身份验证 +- **企业微信**:通过HTTPS协议传输,使用webhook URL进行身份验证 + +```mermaid +flowchart LR +subgraph Security +Credential["凭证管理"] +Transport["传输加密"] +end +Credential --> Isolation["配置隔离"] +Credential --> Encryption["加密存储"] +Credential --> LeastPrivilege["最小权限"] +Transport --> DingTalk["钉钉: HMAC-SHA256"] +Transport --> Email["邮件: STARTTLS/SSL"] +Transport --> Lark["飞书: HTTPS + 访问令牌"] +Transport --> Wecom["企业微信: HTTPS + webhook"] +Isolation --> BestPractice["安全最佳实践"] +Encryption --> BestPractice +LeastPrivilege --> BestPractice +DingTalk --> BestPractice +Email --> BestPractice +Lark --> BestPractice +Wecom --> BestPractice +``` + +**图示来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L96-L109) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L154-L163) +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java#L67) +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L54) + +**本节来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L96-L109) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L154-L163) +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java#L67) +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L54) + +## 开发指南 + +### 创建新的告警通道插件 + +要创建一个新的告警通道插件,需要遵循以下步骤: + +1. **创建Maven模块**:在`datavines-notification-plugins`目录下创建新的模块 +2. **实现SlasHandlerPlugin接口**:创建主类实现`SlasHandlerPlugin`接口 +3. **定义配置实体**:创建接收者配置类,通常包含通道特定的配置参数 +4. **实现发送器**:创建发送器类,负责构建消息和发送HTTP请求 +5. **注册SPI**:在`resources/META-INF/plugins/`目录下创建SPI配置文件 + +### 配置参数定义 + +使用`PluginParams`体系定义配置参数,支持多种输入类型: +- `InputParam`:文本输入框 +- `RadioParam`:单选按钮 +- `SelectParam`:下拉选择框 +- `CheckboxParam`:复选框 + +配置参数应包含验证规则,如必填项、格式验证等。 + +### 消息构建最佳实践 + +- **保持消息简洁**:告警消息应突出关键信息,避免冗长 +- **使用结构化格式**:对于复杂消息,使用JSON数组组织内容 +- **支持动态链接**:将相关记录转换为可点击的链接,方便快速定位问题 +- **考虑多语言**:消息内容应支持国际化,适应不同语言环境 + +### 测试与调试 + +- **单元测试**:为插件和发送器编写单元测试,验证核心功能 +- **集成测试**:在真实环境中测试通知发送,验证配置的正确性 +- **日志监控**:通过日志监控发送状态,及时发现和解决问题 +- **错误模拟**:测试各种错误场景,确保错误处理机制的可靠性 + +**本节来源** +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java#L28-L42) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L39-L133) +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L43-L224) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266\345\274\200\345\217\221.md" "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266\345\274\200\345\217\221.md" new file mode 100644 index 00000000..ebea8e01 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266\345\274\200\345\217\221.md" @@ -0,0 +1,256 @@ +# 执行引擎插件开发 + + +**本文档引用的文件** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + + +## 目录 +1. [引言](#引言) +2. [核心接口与抽象基类](#核心接口与抽象基类) +3. [执行引擎实现示例](#执行引擎实现示例) +4. [执行参数解析与命令行构造](#执行参数解析与命令行构造) +5. [不同执行平台的适配方法](#不同执行平台的适配方法) +6. [日志收集、错误处理与资源清理](#日志收集错误处理与资源清理) +7. [总结](#总结) + +## 引言 +DataVines 是一个数据质量检测框架,支持通过插件化方式扩展不同的执行引擎。本指南旨在为开发者提供详细的执行引擎插件开发说明,涵盖 `EngineExecutor` 接口的核心方法、`RuntimeEnvironment` 的配置方式,并通过 Spark、Flink 和本地执行引擎的实现示例,展示任务提交、状态监控和结果获取的具体流程。同时,本文还将介绍如何适配 Yarn、Livy 和本地等不同执行平台,以及执行参数解析、命令行构造的最佳实践。 + +## 核心接口与抽象基类 + +### EngineExecutor 接口 +`EngineExecutor` 是所有执行引擎的核心接口,定义了执行器的生命周期方法。开发者需实现该接口以支持新的执行引擎。 + +```mermaid +classDiagram +class EngineExecutor { +<> ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++isCancel() boolean ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest +} +``` + +**接口说明:** +- `init`: 初始化执行器,接收任务请求、日志记录器和配置信息。 +- `execute`: 执行任务的核心方法。 +- `after`: 执行完成后执行的清理或后续操作。 +- `cancel`: 取消正在运行的任务。 +- `isCancel`: 判断任务是否已被取消。 +- `getProcessResult`: 获取任务执行结果。 +- `getTaskRequest`: 获取任务请求对象。 + +**代码来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) + +### RuntimeEnvironment 接口 +`RuntimeEnvironment` 定义了运行时环境的准备和执行上下文获取方法,是执行环境的基础接口。 + +```mermaid +classDiagram +class RuntimeEnvironment { +<> ++prepare() void ++getExecution() Execution +} +``` + +**接口说明:** +- `prepare`: 准备运行时环境,如初始化资源、加载配置等。 +- `getExecution`: 获取具体的执行实例,用于执行数据处理流程。 + +**代码来源** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java#L23-L28) + +### Execution 接口 +`Execution` 接口定义了数据处理流程的执行方法,支持源(Source)、转换(Transform)和汇(Sink)组件的执行。 + +```mermaid +classDiagram +class Execution { +<> ++execute(SR[], TF[], SK[]) void ++stop() void ++prepare() void +} +``` + +**代码来源** +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java#L23-L30) + +### 抽象基类体系 +DataVines 提供了多个抽象基类来简化执行器的开发: +- `AbstractEngineExecutor`: 所有执行器的基类,提供通用字段和日志处理方法。 +- `AbstractYarnEngineExecutor`: 针对 Yarn 平台的执行器基类,封装了 Yarn 应用程序的取消和杀死逻辑。 +- `AbstractLivyEngineExecutor`: 针对 Livy 服务的执行器基类,封装了与 Livy REST API 的交互逻辑。 + +```mermaid +classDiagram +class AbstractEngineExecutor { +-jobExecutionRequest JobExecutionRequest +-logger Logger +-cancel boolean +-processResult ProcessResult ++logHandle(String[]) void ++isCancel() boolean ++buildCommand() String +} +class AbstractYarnEngineExecutor { +-shellCommandProcess ShellCommandProcess ++cancel() void +-killYarnApplication() void +} +class AbstractLivyEngineExecutor { +-livyCommandProcess LivyCommandProcess ++cancel() void +} +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +AbstractEngineExecutor <|-- AbstractLivyEngineExecutor +``` + +**代码来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L59) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java#L23-L36) + +## 执行引擎实现示例 + +### Spark 执行引擎 +`SparkEngineExecutor` 继承自 `AbstractYarnEngineExecutor`,通过 `spark-submit` 命令提交任务到 Yarn 集群。 + +**核心流程:** +1. 解析 `engineParameter` 获取 Spark 参数。 +2. 构建 `spark-submit` 命令行。 +3. 使用 `ShellCommandProcess` 执行命令并监控结果。 + +```mermaid +sequenceDiagram +participant JobRunner +participant SparkEngineExecutor +participant ShellCommandProcess +participant Yarn +JobRunner->>SparkEngineExecutor : init() +JobRunner->>SparkEngineExecutor : execute() +SparkEngineExecutor->>SparkEngineExecutor : buildCommand() +SparkEngineExecutor->>ShellCommandProcess : run(command) +ShellCommandProcess->>Yarn : spark-submit +Yarn-->>ShellCommandProcess : Application ID +ShellCommandProcess-->>SparkEngineExecutor : ProcessResult +SparkEngineExecutor-->>JobRunner : getProcessResult() +``` + +**代码来源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L152) + +### Flink 执行引擎 +`FlinkEngineExecutor` 同样继承自 `AbstractYarnEngineExecutor`,通过 `flink` 命令提交任务。 + +**特点:** +- 使用 `FlinkArgsUtils` 工具类构建 Flink 命令行参数。 +- 支持通过 `--conf spark.yarn.tags` 标记任务。 + +**代码来源** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L38-L182) + +### 本地执行引擎 +`LocalEngineExecutor` 直接在当前 JVM 中执行任务,适用于调试和轻量级场景。 + +**特点:** +- 不需要构建命令行,直接调用 `LocalDataVinesBootstrap` 执行。 +- `buildCommand()` 方法返回 `null`。 + +**代码来源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L27-L77) + +### Livy 执行引擎 +`LivyEngineExecutor` 继承自 `AbstractLivyEngineExecutor`,通过 Livy REST API 提交 Spark 任务。 + +**核心流程:** +1. 构建 JSON 格式的 Livy 请求体。 +2. 调用 `post2LivyWithRetry` 发送请求。 +3. 监控任务状态并获取结果。 + +```mermaid +sequenceDiagram +participant JobRunner +participant LivyEngineExecutor +participant LivyCommandProcess +participant LivyServer +JobRunner->>LivyEngineExecutor : init() +JobRunner->>LivyEngineExecutor : execute() +LivyEngineExecutor->>LivyEngineExecutor : buildCommand() +LivyEngineExecutor->>LivyCommandProcess : post2LivyWithRetry(json) +LivyCommandProcess->>LivyServer : POST /sessions +LivyServer-->>LivyCommandProcess : Session ID +LivyCommandProcess->>LivyCommandProcess : processResultOfLivyState() +LivyCommandProcess-->>LivyEngineExecutor : ProcessResult +LivyEngineExecutor-->>JobRunner : getProcessResult() +``` + +**代码来源** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java#L42-L236) + +## 执行参数解析与命令行构造 + +### 参数解析 +执行参数通过 `JSONUtils.parseObject()` 从 `JobExecutionRequest` 中解析: +- `engineParameter`: 引擎特定参数(如 Spark/Flink 配置)。 +- `applicationParameter`: 应用级参数(如数据质量规则配置)。 + +### 命令行构造 +各执行器通过 `buildCommand()` 方法构造命令行: +- **Spark/Flink**: 拼接 `spark-submit` 或 `flink` 命令及参数。 +- **Livy**: 构造 JSON 请求体,包含 `file`, `jars`, `args`, `conf` 等字段。 + +**最佳实践:** +- 使用 `Base64` 编码应用参数,避免命令行长度限制。 +- 动态获取 `SPARK_HOME` 或 `FLINK_HOME` 路径。 +- 支持插件目录的自动发现和 JAR 包加载。 + +## 不同执行平台的适配方法 + +| 平台 | 适配方式 | 关键类 | +|------|---------|--------| +| Yarn | 通过 `spark-submit` 或 `flink` 命令提交 | `AbstractYarnEngineExecutor`, `ShellCommandProcess` | +| Livy | 通过 REST API 提交 Spark 任务 | `AbstractLivyEngineExecutor`, `LivyCommandProcess` | +| 本地 | 直接在 JVM 内执行 | `LocalEngineExecutor`, `LocalDataVinesBootstrap` | + +**适配要点:** +- **Yarn**: 需处理 `sudo -u` 权限和 `yarn application -kill` 命令。 +- **Livy**: 需处理会话生命周期和状态轮询。 +- **本地**: 需确保类路径正确,避免资源冲突。 + +## 日志收集、错误处理与资源清理 + +### 日志收集 +通过 `logHandle(List logs)` 方法统一处理日志输出: +- 将日志信息格式化后输出到 `logger.info()`。 +- 支持多行日志的拼接和展示。 + +**代码来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L45-L48) + +### 错误处理 +- 在 `execute()` 方法中捕获异常并重新抛出。 +- 记录详细的错误日志,便于问题排查。 + +### 资源清理 +- `after()` 方法用于执行清理操作。 +- `cancel()` 方法确保任务被正确终止,释放资源。 + +## 总结 +本文详细介绍了 DataVines 执行引擎插件的开发方法,涵盖了核心接口、抽象基类、具体实现示例以及平台适配策略。开发者可以基于 `EngineExecutor` 接口和提供的抽象基类,快速实现新的执行引擎插件,满足不同场景下的数据质量检测需求。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\217\222\344\273\266\345\274\200\345\217\221.md" "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\217\222\344\273\266\345\274\200\345\217\221.md" new file mode 100644 index 00000000..e4d44df0 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\217\222\344\273\266\345\274\200\345\217\221.md" @@ -0,0 +1,246 @@ +# 插件开发 + + +**本文档中引用的文件** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [NotificationSender.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/NotificationSender.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) + + +## 目录 +1. [简介](#简介) +2. [SPI机制原理](#spi机制原理) +3. [数据源插件开发](#数据源插件开发) +4. [检查规则插件开发](#检查规则插件开发) +5. [执行引擎插件开发](#执行引擎插件开发) +6. [告警通道插件开发](#告警通道插件开发) +7. [注册中心插件开发](#注册中心插件开发) +8. [插件配置与服务发现](#插件配置与服务发现) +9. [插件打包与部署](#插件打包与部署) +10. [插件调试与测试](#插件调试与测试) +11. [版本管理与兼容性](#版本管理与兼容性) +12. [最佳实践](#最佳实践) + +## 简介 +DataVines 是一个基于插件架构设计的数据质量服务平台,支持多种类型的插件扩展,包括数据源、检查规则、执行引擎、告警通道和注册中心。本指南详细介绍了如何为 DataVines 开发各类插件,涵盖 SPI 机制的工作原理、接口实现、配置管理、打包部署、调试测试以及版本兼容性等完整开发生命周期。 + +## SPI机制原理 +DataVines 使用自定义的 SPI(Service Provider Interface)机制来实现插件的动态加载和管理。核心类 `PluginLoader` 负责加载标注了 `@SPI` 注解的接口实现类。 + +`PluginLoader` 通过读取 `META-INF/plugins/` 目录下的配置文件,根据接口全限定名查找对应的实现类。每个插件配置文件以接口名命名,内容为 `插件名称=实现类全限定名` 的键值对格式。`PluginLoader` 支持单例模式获取插件实例(`getOrCreatePlugin`),确保同一名称的插件在 JVM 中只有一个实例。 + +`@SPI` 注解用于标记可扩展的接口,其 `value` 属性可指定默认插件名称。`PluginLoader` 在加载时会验证实现类是否为接口的子类型,并通过 `findAnnotationName` 方法自动推断未在配置文件中显式命名的插件名称(通常为类名去掉接口后缀并转为小写)。 + +```mermaid +classDiagram +class PluginLoader~T~ { ++getPluginLoader(Class~T~ type) PluginLoader~T~ ++getOrCreatePlugin(String name) T ++getSupportedPlugins() Set~String~ +-loadPluginClasses() Map~String, Class~? +-loadResource(Map~String, Class~?, ClassLoader, URL) +-loadClass(Map~String, Class~?, URL, Class~?, String) +} +class SPI { ++String value() +} +PluginLoader --> SPI : "使用" +``` + +**图示来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L51-L487) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) + +## 数据源插件开发 +数据源插件用于连接和操作不同的数据库系统。开发者需要实现 `Connector` 接口,并提供相应的 `DataSourceClient` 和 `Executor` 实现。 + +`Connector` 接口定义了创建数据源客户端和执行器的方法。`DataSourceClient` 负责获取数据库的元数据信息(如数据库、表、列等),而 `Executor` 则负责执行 SQL 查询和脚本。开发者通常需要继承 `JdbcConnector` 或 `JdbcDataSourceClient` 等基类来简化 JDBC 类型数据源的开发。 + +插件实现类需在 `META-INF/plugins/` 目录下创建以 `io.datavines.connector.api.Connector` 命名的配置文件,并添加 `插件名称=实现类全限定名` 的条目。例如,MySQL 插件的配置为 `mysql=io.datavines.connector.plugin.mysql.MySQLConnector`。 + +```mermaid +classDiagram +class Connector { ++createDataSourceClient(Config config) DataSourceClient ++createExecutor(Config config) Executor +} +class DataSourceClient { ++getDatabases() String[] ++getTables(String database) String[] ++getColumns(String database, String table) QueryColumn[] +} +class Executor { ++executeQuery(String sql) ResultListWithColumns ++executeUpdate(String sql) int +} +class JdbcConnector { ++createDataSourceClient(Config config) JdbcDataSourceClient ++createExecutor(Config config) BaseJdbcExecutor +} +Connector <|-- JdbcConnector +JdbcConnector --> JdbcDataSourceClient : "创建" +JdbcConnector --> BaseJdbcExecutor : "创建" +DataSourceClient <|.. JdbcDataSourceClient +Executor <|.. BaseJdbcExecutor +``` + +**图示来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L15) + +**本节来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L15) + +## 检查规则插件开发 +检查规则插件用于定义数据质量的校验逻辑。核心接口是 `SqlMetric`,它定义了生成用于数据质量检查的 SQL 语句的方法。 + +`SqlMetric` 接口的实现需要根据配置的参数(如表名、列名、阈值等)生成相应的 SQL 查询。查询结果将用于判断数据质量是否达标。例如,`column_not_null` 规则会生成 `SELECT COUNT(*) FROM table WHERE column IS NULL` 这样的 SQL 来统计空值数量。 + +开发者需要实现 `SqlMetric` 接口,并在 `META-INF/plugins/` 目录下创建 `io.datavines.metric.api.SqlMetric` 配置文件。插件名称通常与规则类型一致,如 `column_not_null`。 + +```mermaid +classDiagram +class SqlMetric { ++getSql(Config config) String ++getActualValueColumnName() String ++getExpectedValueColumnName() String +} +class ColumnNotNullMetric { ++getSql(Config config) String +} +class ColumnDuplicateMetric { ++getSql(Config config) String +} +SqlMetric <|.. ColumnNotNullMetric +SqlMetric <|.. ColumnDuplicateMetric +``` + +**图示来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L1-L15) + +**本节来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L1-L15) + +## 执行引擎插件开发 +执行引擎插件负责提交和管理数据质量检查任务的执行。核心接口是 `EngineExecutor`,它定义了任务提交、状态查询和日志获取等方法。 + +`EngineExecutor` 的实现需要能够与底层计算框架(如 Spark、Flink)进行交互。例如,`SparkEngineExecutor` 会通过 `spark-submit` 命令或 Livy 服务提交任务。开发者需要实现 `submitJob`、`getJobStatus`、`getJobLog` 等关键方法。 + +插件需在 `META-INF/plugins/` 目录下创建 `io.datavines.engine.api.engine.EngineExecutor` 配置文件。DataVines 内置了 `local` 和 `spark` 两种执行引擎。 + +```mermaid +classDiagram +class EngineExecutor { ++submitJob(JobConfiguration jobConfig) String ++getJobStatus(String jobId) ExecutionStatus ++getJobLog(String jobId, int fromLine, int size) LogResult ++killJob(String jobId) boolean +} +class SparkEngineExecutor { ++submitJob(JobConfiguration jobConfig) String +} +class LocalEngineExecutor { ++submitJob(JobConfiguration jobConfig) String +} +EngineExecutor <|.. SparkEngineExecutor +EngineExecutor <|.. LocalEngineExecutor +``` + +**图示来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L1-L15) + +**本节来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L1-L15) + +## 告警通道插件开发 +告警通道插件用于在数据质量检查失败时发送通知。核心接口是 `NotificationSender`,它定义了发送通知消息的方法。 + +`NotificationSender` 的实现需要能够调用具体的告警服务 API,如邮件服务器、钉钉机器人、企业微信等。`send` 方法接收一个包含告警内容的 `NotificationRequest` 对象,并返回发送结果。 + +开发者需实现 `NotificationSender` 接口,并在 `META-INF/plugins/` 目录下创建 `io.datavines.notification.api.spi.NotificationSender` 配置文件。DataVines 已支持邮件、钉钉、飞书和企业微信机器人等告警通道。 + +```mermaid +classDiagram +class NotificationSender { ++send(NotificationRequest request) boolean +} +class EmailNotificationSender { ++send(NotificationRequest request) boolean +} +class DingTalkNotificationSender { ++send(NotificationRequest request) boolean +} +NotificationSender <|.. EmailNotificationSender +NotificationSender <|.. DingTalkNotificationSender +``` + +**图示来源** +- [NotificationSender.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/NotificationSender.java#L1-L15) + +**本节来源** +- [NotificationSender.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/NotificationSender.java#L1-L15) + +## 注册中心插件开发 +注册中心插件用于实现服务发现和分布式协调。核心接口是 `Registry`,它定义了服务注册、发现和监听的方法。 + +`Registry` 的实现需要能够与注册中心服务(如 ZooKeeper、MySQL)进行交互。`register` 方法用于注册服务实例,`subscribe` 方法用于监听服务列表的变化。 + +开发者需实现 `Registry` 接口,并在 `META-INF/plugins/` 目录下创建 `io.datavines.registry.api.Registry` 配置文件。DataVines 支持 MySQL、PostgreSQL 和 ZooKeeper 作为注册中心。 + +```mermaid +classDiagram +class Registry { ++register(ServerInfo serverInfo) void ++unregister(ServerInfo serverInfo) void ++subscribe(String service, SubscribeListener listener) void ++unsubscribe(String service, SubscribeListener listener) void +} +class MySQLRegistry { ++register(ServerInfo serverInfo) void +} +class ZooKeeperRegistry { ++register(ServerInfo serverInfo) void +} +Registry <|.. MySQLRegistry +Registry <|.. ZooKeeperRegistry +``` + +**图示来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L1-L15) + +**本节来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L1-L15) + +## 插件配置与服务发现 +插件的配置主要通过 `Config` 对象传递。`Config` 是一个键值对集合,包含了插件运行所需的所有参数。例如,数据源插件需要 `host`、`port`、`username`、`password` 等配置项。 + +服务发现依赖于注册中心插件。当多个 `datavines-server` 实例启动时,它们会通过 `Registry` 接口向注册中心注册自己的信息(如 IP、端口)。其他组件(如 `datavines-runner`)可以通过订阅服务列表来发现可用的服务器,并实现负载均衡。 + +## 插件打包与部署 +插件开发完成后,需要将其打包成 JAR 文件。JAR 包中必须包含 `META-INF/plugins/` 目录及其下的配置文件。对于数据源插件,还需要将数据库的 JDBC 驱动 JAR 包一并放入 `datavines-connector-plugins` 模块的 `lib` 目录中。 + +部署时,将插件 JAR 包和依赖的驱动 JAR 包复制到 `datavines/lib/plugins/` 目录下。重启 DataVines 服务后,`PluginLoader` 会自动扫描并加载新插件。 + +## 插件调试与测试 +建议使用单元测试来验证插件的核心逻辑。对于数据源插件,可以编写测试用例来验证 `getDatabases`、`getTables` 等方法是否能正确返回元数据。对于检查规则插件,应测试 `getSql` 方法生成的 SQL 语句是否正确。 + +集成测试可以通过启动一个本地的 DataVines 环境,配置使用待测试的插件,并执行一个数据质量检查任务来完成。观察任务执行日志和结果,可以验证插件是否按预期工作。 + +## 版本管理与兼容性 +插件的版本管理应遵循语义化版本规范(SemVer)。主版本号的变更通常意味着不兼容的 API 修改。为保证兼容性,建议: + +1. 避免修改已发布的 `SPI` 接口。 +2. 通过添加新方法或新配置项来扩展功能,而不是修改现有行为。 +3. 在 `PluginLoader` 中,优先加载显式配置的插件,以避免因自动推断名称导致的冲突。 +4. 在插件 JAR 包的 `MANIFEST.MF` 文件中声明兼容的 DataVines 核心版本。 + +## 最佳实践 +1. **遵循命名规范**:插件名称应简洁、明确,使用小写字母和下划线。 +2. **提供默认实现**:在 `@SPI` 注解中指定一个可靠的默认插件。 +3. **处理异常**:在插件代码中妥善处理可能的异常,并提供清晰的错误信息。 +4. **资源管理**:对于需要管理连接、会话等资源的插件,确保在适当时机进行资源释放。 +5. **日志记录**:使用 SLF4J 记录关键操作和错误,便于问题排查。 +6. **配置校验**:在插件初始化时,对传入的 `Config` 对象进行必要的校验。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\225\260\346\215\256\346\272\220\346\217\222\344\273\266\345\274\200\345\217\221.md" "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\225\260\346\215\256\346\272\220\346\217\222\344\273\266\345\274\200\345\217\221.md" new file mode 100644 index 00000000..67008720 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\225\260\346\215\256\346\272\220\346\217\222\344\273\266\345\274\200\345\217\221.md" @@ -0,0 +1,551 @@ +# 数据源插件开发 + + +**本文档中引用的文件** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) +- [MysqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDialect.java) +- [MysqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnectorFactory.java) +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) + + +## 目录 +1. [引言](#引言) +2. [核心接口详解](#核心接口详解) +3. [JDBC基础实现](#jdbc基础实现) +4. [MySQL插件实现示例](#mysql插件实现示例) +5. [PostgreSQL插件实现示例](#postgresql插件实现示例) +6. [连接池与事务管理](#连接池与事务管理) +7. [错误恢复机制](#错误恢复机制) +8. [插件测试指南](#插件测试指南) +9. [插件打包与部署](#插件打包与部署) +10. [SPI机制注册](#spi机制注册) + +## 引言 +DataVines是一个数据质量监控平台,支持通过插件机制扩展数据源。本文档详细介绍如何为DataVines开发新的数据源插件,涵盖Connector、DataSourceClient和Dialect接口的作用和实现方法。通过MySQL和PostgreSQL插件的实现示例,展示如何处理连接配置、SQL方言差异和元数据获取。同时涵盖连接池管理、事务处理和错误恢复机制,指导开发者如何测试插件的兼容性和性能,并提供插件打包和部署的详细步骤。 + +## 核心接口详解 + +### Connector接口 +Connector接口是数据源插件的核心接口,定义了与数据源交互的基本操作。它提供了获取数据库、表、列等元数据的方法,以及测试连接的功能。 + +```mermaid +classDiagram +class Connector { ++getDatabases(GetDatabasesRequestParam) ConnectorResponse ++getTables(GetTablesRequestParam) ConnectorResponse ++getColumns(GetColumnsRequestParam) ConnectorResponse ++getPartitions(ConnectorRequestParam) ConnectorResponse ++testConnect(TestConnectionRequestParam) ConnectorResponse ++keyProperties() String[] +} +``` + +**接口来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) + +### DataSourceClient接口 +DataSourceClient接口负责管理数据源连接,提供获取DataSource、Connection和JdbcTemplate的方法。它抽象了底层连接管理的复杂性,使上层代码可以专注于业务逻辑。 + +```mermaid +classDiagram +class DataSourceClient { ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map~String,Object~) DataSource ++getDataSource(Properties) DataSource ++getConnection(BaseJdbcDataSourceInfo) Connection ++getConnection(Map~String,Object~) Connection ++getConnection(Map~String,Object~, Logger) Connection ++getConnection(Properties) Connection ++getJdbcTemplate(BaseJdbcDataSourceInfo) JdbcTemplate +} +``` + +**接口来源** +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) + +### Dialect接口 +Dialect接口处理SQL方言的差异,提供数据库特定的SQL生成和处理功能。它定义了驱动类名、标识符引号、排除的数据库列表等属性,以及各种SQL查询的生成方法。 + +```mermaid +classDiagram +class Dialect { ++getDriver() String ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++getFullQualifiedTableName(String, String, String, boolean) String ++invalidateItemCanOutput() boolean ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++getJDBCType(DataType) String ++getDataType(String) DataType ++quoteIdentifier(String) String ++getQuoteIdentifier() String ++getTableExistsQuery(String) String ++getSchemaQuery(String) String ++getCountQuery(String) String ++getSelectQuery(String) String ++getCreateTableAsSelectStatement(String, String, String) String ++getCreateTableAsSelectStatementFromSql(String, String, String) String ++getCreateTableStatement(String, StructField[], TypeConverter) String ++getInsertAsSelectStatement(String, String, String) String ++getInsertAsSelectStatementFromSql(String, String, String) String ++getErrorDataScript(Map~String, String~) String ++getValidateResultDataScript(Map~String, String~) String ++getPageFromResultSet(Statement, ResultSet, String, int, int) ResultList +} +``` + +**接口来源** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) + +### ConnectorFactory接口 +ConnectorFactory接口是插件工厂,负责创建和配置插件所需的各个组件。通过SPI机制注册,DataVines在运行时动态加载相应的插件工厂。 + +```mermaid +classDiagram +class ConnectorFactory { ++getCategory() String ++getConnector() Connector ++getResponseConverter() ResponseConverter ++getDialect() Dialect ++getConnectorParameterConverter() ParameterConverter ++getExecutor() Executor ++getTypeConverter() TypeConverter ++getConfigBuilder() ConfigBuilder ++getDataSourceClient() DataSourceClient ++getStatementSplitter() StatementSplitter ++getStatementParser() StatementParser ++getMetricScript() MetricScript ++showInFrontend() Boolean +} +``` + +**接口来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +### Executor接口 +Executor接口负责执行SQL脚本和查询,提供分页查询、列表查询和单条记录查询等功能。它是数据操作的执行层,封装了具体的执行逻辑。 + +```mermaid +classDiagram +class Executor { ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse ++deleteData(ExecuteRequestParam) ConnectorResponse +} +``` + +**接口来源** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) + +## JDBC基础实现 + +### JdbcConnector抽象类 +JdbcConnector是所有JDBC数据源插件的基础实现,提供了获取数据库、表、列等元数据的通用方法。它继承了Connector接口,并实现了大部分通用功能。 + +```mermaid +classDiagram +class JdbcConnector { +-logger Logger +-TABLE String +-VIEW String +-TABLE_TYPES String[] +-TABLE_NAME String +-TABLE_TYPE String +-dataSourceClient DataSourceClient ++JdbcConnector(DataSourceClient) ++getDatabases(GetDatabasesRequestParam) ConnectorResponse ++getTables(GetTablesRequestParam) ConnectorResponse ++getColumns(GetColumnsRequestParam) ConnectorResponse ++getPartitions(ConnectorRequestParam) ConnectorResponse ++testConnect(TestConnectionRequestParam) ConnectorResponse ++keyProperties() String[] ++getMetadataDatabases(Connection) ResultSet ++getMetadataTables(DatabaseMetaData, String, String) ResultSet ++getMetadataColumns(DatabaseMetaData, String, String, String, String) ResultSet ++getPrimaryKeys(DatabaseMetaData, String, String, String) ResultSet +} +``` + +**实现来源** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +### JdbcDataSourceClient实现 +JdbcDataSourceClient实现了DataSourceClient接口,利用JdbcDataSourceManager管理连接池,提供DataSource、Connection和JdbcTemplate的获取功能。 + +```mermaid +classDiagram +class JdbcDataSourceClient { ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map~String, Object~) DataSource ++getDataSource(Properties) DataSource ++getConnection(BaseJdbcDataSourceInfo) Connection ++getConnection(Map~String, Object~) Connection ++getConnection(Map~String, Object~, Logger) Connection ++getConnection(Properties) Connection ++getJdbcTemplate(BaseJdbcDataSourceInfo) JdbcTemplate +} +``` + +**实现来源** +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) + +### JdbcDialect抽象类 +JdbcDialect是所有JDBC方言的基础实现,提供了默认的SQL生成逻辑和标识符引号处理。具体数据库的方言类可以继承它并重写特定方法。 + +```mermaid +classDiagram +class JdbcDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++getErrorDataScript(Map~String, String~) String ++getValidateResultDataScript(Map~String, String~) String ++getPageFromResultSet(Statement, ResultSet, String, int, int) ResultList +} +``` + +**实现来源** +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) + +### AbstractJdbcConnectorFactory抽象类 +AbstractJdbcConnectorFactory是所有JDBC插件工厂的基础实现,提供了通用的组件创建逻辑,如ResponseConverter、TypeConverter、ConfigBuilder等。 + +```mermaid +classDiagram +class AbstractJdbcConnectorFactory { ++getCategory() String ++getResponseConverter() ResponseConverter ++getTypeConverter() TypeConverter ++getConfigBuilder() ConfigBuilder ++getDataSourceClient() DataSourceClient ++getStatementSplitter() StatementSplitter ++getStatementParser() StatementParser ++getMetricScript() MetricScript +} +``` + +**实现来源** +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java) + +### BaseJdbcExecutor抽象类 +BaseJdbcExecutor是所有JDBC执行器的基础实现,提供了基于JdbcTemplate的查询功能,包括分页查询、列表查询和单条记录查询。 + +```mermaid +classDiagram +class BaseJdbcExecutor { +-dataSourceClient DataSourceClient ++BaseJdbcExecutor(DataSourceClient) ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++query(JdbcTemplate, String, int) ListWithQueryColumn +} +``` + +**实现来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +## MySQL插件实现示例 + +### MysqlConnector实现 +MysqlConnector继承了JdbcConnector,实现了MySQL特定的元数据获取逻辑,特别是通过getMetadataDatabases方法使用DatabaseMetaData.getCatalogs()获取数据库列表。 + +```mermaid +classDiagram +class MysqlConnector { ++MysqlConnector(DataSourceClient) ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo ++getMetadataDatabases(Connection) ResultSet +} +``` + +**实现来源** +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) + +### MysqlDialect实现 +MysqlDialect继承了JdbcDialect,定义了MySQL特定的驱动类名、标识符引号和错误数据存储支持。它重写了getDriver方法返回"com.mysql.cj.jdbc.Driver"。 + +```mermaid +classDiagram +class MysqlDialect { ++getDriver() String ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++quoteIdentifier(String) String ++getQuoteIdentifier() String +} +``` + +**实现来源** +- [MysqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDialect.java) + +### MysqlConnectorFactory实现 +MysqlConnectorFactory继承了AbstractJdbcConnectorFactory,实现了MySQL特定的组件创建逻辑,包括MysqlParameterConverter、MysqlDialect、MysqlExecutor等。 + +```mermaid +classDiagram +class MysqlConnectorFactory { ++getConnectorParameterConverter() ParameterConverter ++getDialect() Dialect ++getConnector() Connector ++getExecutor() Executor ++getConfigBuilder() ConfigBuilder ++getMetricScript() MetricScript +} +``` + +**实现来源** +- [MysqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnectorFactory.java) + +## PostgreSQL插件实现示例 + +### PostgreSqlConnector实现 +PostgreSqlConnector继承了JdbcConnector,实现了PostgreSQL特定的元数据获取逻辑,包括支持"FOREIGN TABLE"类型和使用getMetadataDatabases方法获取数据库列表。 + +```mermaid +classDiagram +class PostgreSqlConnector { +-FOREIGN_TABLE String +-TABLE_TYPES String[] ++PostgreSqlConnector(DataSourceClient) ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo ++getMetadataDatabases(Connection) ResultSet ++getMetadataTables(DatabaseMetaData, String, String) ResultSet +} +``` + +**实现来源** +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) + +### PostgreSqlDialect实现 +PostgreSqlDialect继承了JdbcDialect,定义了PostgreSQL特定的驱动类名"org.postgresql.Driver"。 + +```mermaid +classDiagram +class PostgreSqlDialect { ++getDriver() String +} +``` + +**实现来源** +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) + +## 连接池与事务管理 + +### 连接池管理 +DataVines使用JdbcDataSourceManager管理连接池,通过DataSourceClient接口提供连接获取功能。连接池的配置和管理由JdbcDataSourceManager负责,确保连接的高效复用和资源管理。 + +```mermaid +sequenceDiagram +participant Application +participant DataSourceClient +participant JdbcDataSourceManager +participant ConnectionPool +Application->>DataSourceClient : getConnection(config) +DataSourceClient->>JdbcDataSourceManager : getDataSource(config) +JdbcDataSourceManager->>ConnectionPool : 获取连接 +ConnectionPool-->>JdbcDataSourceManager : 返回连接 +JdbcDataSourceManager-->>DataSourceClient : 返回DataSource +DataSourceClient-->>Application : 返回Connection +``` + +**实现来源** +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +### 事务管理 +DataVines通过JdbcTemplate管理事务,利用Spring的事务管理机制确保数据操作的原子性和一致性。Executor实现类使用JdbcTemplate执行SQL,自动参与当前事务。 + +```mermaid +sequenceDiagram +participant Service +participant Executor +participant JdbcTemplate +participant Database +Service->>Executor : queryForList(param) +Executor->>JdbcTemplate : 执行查询 +JdbcTemplate->>Database : 执行SQL +Database-->>JdbcTemplate : 返回结果 +JdbcTemplate-->>Executor : 返回结果集 +Executor-->>Service : 返回ConnectorResponse +``` + +**实现来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +## 错误恢复机制 + +### 连接错误处理 +DataVines在连接失败时提供详细的错误日志和恢复机制。通过DataSourceClient的getConnection方法,捕获SQLException并记录错误信息,同时提供重试机制。 + +```mermaid +flowchart TD +Start([开始连接]) --> GetConnection["获取连接"] +GetConnection --> ConnectionValid{"连接有效?"} +ConnectionValid --> |否| HandleError["处理连接错误"] +HandleError --> LogError["记录错误日志"] +LogError --> Retry{"是否重试?"} +Retry --> |是| GetConnection +Retry --> |否| ReturnError["返回错误"] +ConnectionValid --> |是| ReturnSuccess["返回成功"] +ReturnSuccess --> End([结束]) +ReturnError --> End +``` + +**实现来源** +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) + +### 查询错误处理 +在执行查询时,DataVines捕获SQLException并返回适当的错误响应。通过ConnectorResponse的status和errorMsg字段,向调用方传递错误信息。 + +```mermaid +flowchart TD +StartQuery([开始查询]) --> ExecuteSQL["执行SQL"] +ExecuteSQL --> SQLSuccess{"执行成功?"} +SQLSuccess --> |否| HandleQueryError["处理查询错误"] +HandleQueryError --> LogQueryError["记录查询错误日志"] +LogQueryError --> BuildErrorResponse["构建错误响应"] +BuildErrorResponse --> ReturnErrorResponse["返回错误响应"] +SQLSuccess --> |是| BuildSuccessResponse["构建成功响应"] +BuildSuccessResponse --> ReturnSuccessResponse["返回成功响应"] +ReturnErrorResponse --> EndQuery([结束]) +ReturnSuccessResponse --> EndQuery +``` + +**实现来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +## 插件测试指南 + +### 单元测试 +为确保插件的正确性,需要编写全面的单元测试。测试应覆盖连接、元数据获取、查询执行等核心功能。 + +```mermaid +flowchart TD +TestSuite([测试套件]) --> TestConnect["测试连接"] +TestSuite --> TestGetDatabases["测试获取数据库"] +TestSuite --> TestGetTables["测试获取表"] +TestSuite --> TestGetColumns["测试获取列"] +TestSuite --> TestQuery["测试查询"] +TestConnect --> MockDataSource["模拟数据源"] +MockDataSource --> ExecuteTest["执行连接测试"] +ExecuteTest --> VerifyResult["验证结果"] +TestGetDatabases --> MockConnection["模拟连接"] +MockConnection --> ExecuteGetDatabases["执行获取数据库测试"] +ExecuteGetDatabases --> VerifyDatabases["验证数据库列表"] +TestGetTables --> ExecuteGetTables["执行获取表测试"] +ExecuteGetTables --> VerifyTables["验证表列表"] +TestGetColumns --> ExecuteGetColumns["执行获取列测试"] +ExecuteGetColumns --> VerifyColumns["验证列信息"] +TestQuery --> ExecuteQuery["执行查询测试"] +ExecuteQuery --> VerifyQueryResult["验证查询结果"] +``` + +### 集成测试 +集成测试需要在真实环境中验证插件的功能,包括连接池管理、事务处理和错误恢复等。 + +```mermaid +sequenceDiagram +participant Test +participant Plugin +participant Database +Test->>Plugin : 初始化插件 +Plugin->>Database : 建立连接 +Database-->>Plugin : 返回连接 +Plugin-->>Test : 插件初始化完成 +Test->>Plugin : 获取数据库列表 +Plugin->>Database : 查询数据库 +Database-->>Plugin : 返回数据库列表 +Plugin-->>Test : 返回数据库列表 +Test->>Plugin : 执行查询 +Plugin->>Database : 执行SQL +Database-->>Plugin : 返回查询结果 +Plugin-->>Test : 返回查询结果 +Test->>Plugin : 关闭连接 +Plugin->>Database : 关闭连接 +Database-->>Plugin : 连接关闭 +Plugin-->>Test : 插件关闭完成 +``` + +## 插件打包与部署 + +### Maven项目结构 +数据源插件通常作为Maven项目开发,需要遵循特定的目录结构和依赖配置。 + +```mermaid +graph TD +ProjectRoot([项目根目录]) --> pom.xml +ProjectRoot --> src +src --> main +main --> java +java --> io.datavines.connector.plugin +io.datavines.connector.plugin --> Connector.java +io.datavines.connector.plugin --> Dialect.java +io.datavines.connector.plugin --> ConnectorFactory.java +main --> resources +resources --> META-INF +META-INF --> plugins +plugins --> connector.factory +``` + +### 打包流程 +插件打包需要生成JAR文件,并包含必要的SPI配置。 + +```mermaid +flowchart TD +StartBuild([开始构建]) --> Compile["编译Java源码"] +Compile --> Package["打包JAR文件"] +Package --> AddSPI["添加SPI配置"] +AddSPI --> META-INF["创建META-INF目录"] +META-INF --> plugins["创建plugins目录"] +plugins --> factoryFile["创建connector.factory文件"] +factoryFile --> WriteClassName["写入工厂类名"] +WriteClassName --> CompleteBuild["构建完成"] +``` + +## SPI机制注册 + +### SPI配置 +通过在META-INF/services目录下创建connector.factory文件,注册插件工厂类,实现SPI机制的自动发现。 + +```mermaid +flowchart TD +SPIConfig([SPI配置]) --> CreateDirectory["创建META-INF/services目录"] +CreateDirectory --> CreateFile["创建connector.factory文件"] +CreateFile --> WriteClassName["写入工厂类全名"] +WriteClassName --> Example["示例: io.datavines.connector.plugin.MysqlConnectorFactory"] +Example --> Complete["配置完成"] +``` + +**实现来源** +- [MysqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnectorFactory.java) + +### 插件加载流程 +DataVines启动时通过SPI机制加载所有注册的插件工厂,实现插件的动态发现和注册。 + +```mermaid +sequenceDiagram +participant DataVines +participant SPI +participant PluginFactory +DataVines->>SPI : ServiceLoader.load(ConnectorFactory.class) +SPI->>PluginFactory : 查找META-INF/services/connector.factory +PluginFactory-->>SPI : 返回工厂类名 +SPI-->>DataVines : 返回工厂实例 +DataVines->>PluginFactory : 注册插件 +PluginFactory-->>DataVines : 插件注册完成 +``` \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\243\200\346\237\245\350\247\204\345\210\231\346\217\222\344\273\266\345\274\200\345\217\221.md" "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\243\200\346\237\245\350\247\204\345\210\231\346\217\222\344\273\266\345\274\200\345\217\221.md" new file mode 100644 index 00000000..b03bbef6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\243\200\346\237\245\350\247\204\345\210\231\346\217\222\344\273\266\345\274\200\345\217\221.md" @@ -0,0 +1,304 @@ +# 检查规则插件开发 + + +**本文档中引用的文件** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [MetricExecutionResult.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricExecutionResult.java) +- [ColumnNotNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-not-null/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java) +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumnNotUseView.java) + + +## 目录 +1. [引言](#引言) +2. [核心接口设计](#核心接口设计) +3. [检查规则实现模式](#检查规则实现模式) +4. [代码示例分析](#代码示例分析) +5. [预期值计算策略](#预期值计算策略) +6. [测试与性能优化](#测试与性能优化) +7. [结论](#结论) + +## 引言 +DataVines是一个数据质量监控平台,支持通过插件化方式扩展数据质量检查规则。本文档旨在为开发者提供详细的检查规则插件开发指南,涵盖从接口设计到具体实现的各个方面。通过本指南,开发者可以了解如何创建自定义的数据质量检查规则,包括单表列检查、跨表准确性检查和自定义聚合SQL检查等不同类型。 + +## 核心接口设计 + +### SqlMetric接口设计原理 +`SqlMetric`接口是DataVines中所有数据质量检查规则的核心接口,定义了检查规则的基本行为和属性。该接口通过SPI(Service Provider Interface)机制实现插件化扩展,允许开发者通过实现该接口来创建自定义的检查规则。 + +```mermaid +classDiagram +class SqlMetric { +<> ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getInvalidateItems(Map) ++ExecuteSql getActualValue(Map) ++ExecuteSql getDirectActualValue(Map) ++String getActualName() ++String getActualValueType() ++CheckResult validateConfig(Map) ++Map getConfigMap() ++void prepare(Map) ++String getIssue() ++List suitableType() ++boolean supportMultiple() ++List> getMetricParameter(Map) ++MetricDirectionType getDirectionType() ++boolean isCustomSql() +} +class ExpectedValue { +<> ++String getName() ++String getZhName() ++String getKey(Map) ++String getExecuteSql(Map) ++String getOutputTable(Map) ++boolean isNeedDefaultDatasource() ++void prepare(Map) +} +class ResultFormula { +<> ++String getName() ++String getZhName() ++BigDecimal getResult(BigDecimal, BigDecimal) ++BigDecimal getScore(BigDecimal, BigDecimal, boolean, MetricDirectionType) ++String getResultFormat(boolean) ++String getSymbol() ++ResultFormulaType getType() +} +SqlMetric <|-- ColumnNotNull : "实现" +SqlMetric <|-- TableRowCount : "实现" +SqlMetric <|-- CustomAggregateSql : "实现" +SqlMetric <|-- MultiTableAccuracy : "实现" +ExpectedValue <|-- DailyAvgExpectedValue : "实现" +ResultFormula <|-- CountResultFormula : "实现" +``` + +**图源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) + +**节源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L29-L111) + +### 接口关键方法说明 +`SqlMetric`接口定义了多个关键方法,用于实现不同类型的数据质量检查: + +- **getActualValue**: 获取实际值的SQL查询,这是所有检查规则的核心,用于计算当前数据的实际质量指标 +- **getInvalidateItems**: 获取无效数据项的SQL查询,用于定位不符合质量要求的具体数据记录 +- **validateConfig**: 验证配置参数的有效性,确保检查规则所需的配置项完整且正确 +- **prepare**: 初始化方法,在执行检查前进行必要的准备工作,如设置过滤条件等 +- **getConfigMap**: 定义检查规则所需的配置项,包括参数名称、描述和类型等信息 + +这些方法共同构成了检查规则的执行流程,从配置验证到实际值计算,再到结果输出的完整生命周期。 + +## 检查规则实现模式 + +### 单表列检查模式 +单表列检查是最常见的数据质量检查类型,主要针对单个表中的特定列进行质量验证。这种模式通常继承`BaseSingleTableColumnNotUseView`基类,该基类提供了基本的列检查功能框架。 + +```mermaid +flowchart TD +Start([开始]) --> ValidateConfig["验证配置参数"] +ValidateConfig --> Prepare["准备检查环境"] +Prepare --> BuildFilter["构建过滤条件"] +BuildFilter --> GetActualValue["获取实际值SQL"] +GetActualValue --> ExecuteSql["执行SQL查询"] +ExecuteSql --> ProcessResult["处理查询结果"] +ProcessResult --> OutputResult["输出检查结果"] +OutputResult --> End([结束]) +subgraph "Prepare阶段" +Prepare --> BuildFilter +end +subgraph "执行阶段" +GetActualValue --> ExecuteSql +ExecuteSql --> ProcessResult +end +``` + +**图源** +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumnNotUseView.java) +- [ColumnNotNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-not-null/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java) + +**节源** +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumnNotUseView.java#L27-L60) + +### 跨表准确性检查模式 +跨表准确性检查用于验证两个或多个表之间的数据一致性,通常用于主从表、源目标表等场景。`MultiTableAccuracy`类实现了这种检查模式,通过LEFT JOIN操作来识别源表中存在但目标表中缺失的记录。 + +```mermaid +sequenceDiagram +participant Source as "源表" +participant Target as "目标表" +participant Join as "JOIN操作" +participant Result as "结果集" +Source->>Join : 提供源表数据 +Target->>Join : 提供目标表数据 +Join->>Join : 执行LEFT JOIN操作 +Join->>Join : 应用ON子句条件 +Join->>Join : 应用WHERE子句过滤 +Join->>Result : 输出不匹配的记录 +Result->>Result : 计算不匹配数量 +Result-->>User : 返回检查结果 +``` + +**图源** +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java#L32-L136) + +**节源** +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java#L32-L136) + +### 自定义聚合SQL检查模式 +自定义聚合SQL检查模式允许用户通过编写自定义的SQL语句来实现复杂的数据质量检查逻辑。`CustomAggregateSql`类实现了这一模式,用户可以直接提供聚合SQL语句,系统会将其包装并执行。 + +```mermaid +flowchart LR +UserInput["用户输入自定义SQL"] --> SqlValidation["SQL语法验证"] +SqlValidation --> SqlProcessing["SQL语句处理"] +SqlProcessing --> UniqueNaming["添加唯一标识符"] +UniqueNaming --> Execution["执行处理后的SQL"] +Execution --> ResultProcessing["结果处理"] +ResultProcessing --> Output["输出检查结果"] +style UserInput fill:#f9f,stroke:#333 +style Output fill:#bbf,stroke:#333 +``` + +**图源** +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java#L35-L118) + +**节源** +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java#L35-L118) + +## 代码示例分析 + +### 非空检查插件实现 +非空检查插件`ColumnNotNull`用于验证指定列中是否存在空值。该插件继承自`BaseSingleTableColumnNotUseView`基类,实现了基本的非空检查逻辑。 + +```mermaid +classDiagram +class ColumnNotNull { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++void prepare(Map) ++List suitableType() +} +class BaseSingleTableColumnNotUseView { ++Map configMap ++Set requiredOptions ++StringBuilder invalidateItemsSql ++BaseSingleTableColumnNotUseView() ++Map getConfigMap() ++MetricLevel getLevel() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getDirectActualValue(Map) +} +BaseSingleTableColumnNotUseView <|-- ColumnNotNull : "继承" +``` + +**图源** +- [ColumnNotNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-not-null/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java#L28-L71) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumnNotUseView.java#L27-L60) + +**节源** +- [ColumnNotNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-not-null/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java#L28-L71) + +### 行数检查插件实现 +行数检查插件`TableRowCount`用于验证表的行数是否符合预期。该插件实现了`getActualValue`方法,生成计算表行数的SQL查询语句。 + +```mermaid +classDiagram +class TableRowCount { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++void prepare(Map) ++Map getConfigMap() ++ExecuteSql getInvalidateItems(Map) ++ExecuteSql getActualValue(Map) ++List suitableType() ++boolean supportMultiple() ++List> getMetricParameter(Map) +} +TableRowCount <|-- BaseSingleTable : "继承" +``` + +**图源** +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java#L32-L126) + +**节源** +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java#L32-L126) + +## 预期值计算策略 + +### 固定值策略 +固定值策略是最简单的预期值计算方式,用户直接在配置中指定一个固定的预期值。这种策略适用于那些预期值不会变化的检查场景,如某些业务规则要求的固定阈值。 + +### 历史平均值策略 +历史平均值策略通过计算历史数据的平均值来确定预期值。DataVines提供了多种时间范围的平均值计算插件,包括: +- 日平均值(daily-avg) +- 近7天平均值(last7day-avg) +- 近30天平均值(last30day-avg) +- 周平均值(weekly-avg) +- 月平均值(monthly-avg) + +这些策略通过`ExpectedValue`接口实现,可以根据不同的业务需求选择合适的时间窗口。 + +```mermaid +flowchart TD +Start([开始]) --> SelectStrategy["选择计算策略"] +SelectStrategy --> DailyAvg["日平均值"] +SelectStrategy --> Last7Day["近7天平均值"] +SelectStrategy --> Last30Day["近30天平均值"] +SelectStrategy --> Weekly["周平均值"] +SelectStrategy --> Monthly["月平均值"] +DailyAvg --> ExecuteSql["执行历史数据查询"] +Last7Day --> ExecuteSql +Last30Day --> ExecuteSql +Weekly --> ExecuteSql +Monthly --> ExecuteSql +ExecuteSql --> CalculateAvg["计算平均值"] +CalculateAvg --> ReturnResult["返回预期值"] +ReturnResult --> End([结束]) +``` + +**图源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java#L24-L64) + +**节源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java#L24-L64) + +## 测试与性能优化 + +### 规则准确性测试 +为确保检查规则的准确性,建议进行以下测试: + +1. **单元测试**:针对每个检查规则编写单元测试,验证其核心逻辑的正确性 +2. **集成测试**:在真实数据环境中测试检查规则,确保其能够正确处理各种数据场景 +3. **边界测试**:测试边界条件,如空表、空列、极端值等情况 +4. **性能测试**:评估检查规则在大数据量下的执行性能 + +### 性能优化建议 +为提高检查规则的执行效率,建议采取以下优化措施: + +1. **SQL优化**:确保生成的SQL语句经过优化,避免全表扫描和不必要的计算 +2. **索引利用**:在查询条件中使用的列上建立适当的索引 +3. **分页处理**:对于大量无效数据的查询,考虑使用分页机制 +4. **缓存机制**:对于频繁使用的计算结果,可以考虑使用缓存 +5. **并行执行**:对于多个独立的检查规则,可以考虑并行执行以提高整体效率 + +## 结论 +DataVines的检查规则插件开发框架提供了灵活而强大的扩展能力,通过实现`SqlMetric`接口,开发者可以创建各种类型的数据质量检查规则。从简单的单表列检查到复杂的跨表准确性验证,框架都提供了相应的支持。通过合理利用基类和继承机制,可以快速开发出符合业务需求的检查规则。同时,结合不同的预期值计算策略,可以实现动态的、基于历史数据的质量监控。建议开发者在开发过程中注重代码的可维护性和性能优化,确保检查规则在生产环境中的稳定运行。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\263\250\345\206\214\344\270\255\345\277\203\346\217\222\344\273\266\345\274\200\345\217\221.md" "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\263\250\345\206\214\344\270\255\345\277\203\346\217\222\344\273\266\345\274\200\345\217\221.md" new file mode 100644 index 00000000..61d4d610 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\217\222\344\273\266\345\274\200\345\217\221/\346\263\250\345\206\214\344\270\255\345\277\203\346\217\222\344\273\266\345\274\200\345\217\221.md" @@ -0,0 +1,320 @@ +# 注册中心插件开发 + + +**本文档中引用的文件** +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ConnectionListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\SubscribeListener.java) +- [Event.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Event.java) +- [ConnectionStatus.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionStatus.java) +- [ServerInfo.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ServerInfo.java) +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java) +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java) +- [CommonPropertyUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\CommonPropertyUtils.java) +- [ZooKeeperConfig.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperConfig.java) + + +## 目录 +1. [引言](#引言) +2. [注册中心接口核心功能](#注册中心接口核心功能) +3. [服务注册与发现机制](#服务注册与发现机制) +4. [ZooKeeper注册中心实现](#zookeeper注册中心实现) +5. [MySQL注册中心实现](#mysql注册中心实现) +6. [分布式锁实现](#分布式锁实现) +7. [服务器状态管理](#服务器状态管理) +8. [连接状态监听与事件通知](#连接状态监听与事件通知) +9. [性能优化建议](#性能优化建议) +10. [高可用性设计考虑](#高可用性设计考虑) + +## 引言 + +DataVines注册中心插件开发指南旨在为开发者提供详细的指导,帮助他们为DataVines开发新的注册中心插件。本指南将深入探讨Registry接口的核心功能和实现要求,包括服务注册、发现和监听机制。通过分析ZooKeeper和MySQL注册中心的实现示例,展示如何处理节点管理、会话维护和故障转移。此外,本指南还将涵盖分布式锁的实现和服务器状态管理,指导开发者如何实现连接状态监听和事件通知,并提供性能优化建议和高可用性设计考虑。 + +**本节不分析具体源文件,因此不提供源引用。** + +## 注册中心接口核心功能 + +DataVines的注册中心插件基于`Registry`接口实现,该接口定义了注册中心的核心功能。`Registry`接口位于`io.datavines.registry.api.Registry`,是所有注册中心插件必须实现的契约。 + +`Registry`接口的主要功能包括: +- **初始化**:`init(Properties properties)`方法用于初始化注册中心,接收配置属性作为参数。 +- **分布式锁**:`acquire(String key, long timeout)`和`release(String key)`方法用于获取和释放分布式锁。 +- **订阅与取消订阅**:`subscribe(String key, SubscribeListener listener)`和`unSubscribe(String key)`方法用于订阅和取消订阅特定键的变更事件。 +- **连接监听**:`addConnectionListener(ConnectionListener connectionListener)`方法用于添加连接状态监听器。 +- **服务器列表获取**:`getActiveServerList()`方法用于获取当前活跃的服务器列表。 +- **关闭**:`close()`方法用于关闭注册中心连接。 + +这些核心功能为DataVines提供了服务发现、配置管理、分布式协调等关键能力。 + +**本节不分析具体源文件,因此不提供源引用。** + +## 服务注册与发现机制 + +DataVines的服务注册与发现机制通过`Registry`接口的实现来完成。当一个DataVines服务器启动时,它会通过注册中心插件将自己的信息注册到注册中心。其他服务器可以通过查询注册中心来发现可用的服务器。 + +在ZooKeeper注册中心实现中,服务器信息被存储在ZooKeeper的持久化节点中。服务器启动时,会创建一个包含其主机名和端口信息的节点。其他服务器可以通过读取该节点的子节点来获取活跃服务器列表。 + +在MySQL注册中心实现中,服务器信息被存储在`dv_server`数据库表中。服务器通过定期更新其心跳时间来表明其活跃状态。其他服务器可以通过查询该表来获取活跃服务器列表。 + +```mermaid +flowchart TD +A[服务器启动] --> B[初始化注册中心] +B --> C[注册服务器信息] +C --> D[开始心跳] +D --> E[其他服务器查询] +E --> F[获取活跃服务器列表] +F --> G[服务发现完成] +``` + +**本节不分析具体源文件,因此不提供源引用。** + +## ZooKeeper注册中心实现 + +ZooKeeper注册中心实现位于`io.datavines.registry.plugin.ZooKeeperRegistry`类中。该实现利用Apache Curator框架与ZooKeeper进行交互。 + +`ZooKeeperRegistry`类的主要组件包括: +- **CuratorFramework client**:ZooKeeper客户端,用于与ZooKeeper集群通信。 +- **InterProcessMutex mutex**:分布式互斥锁,用于实现分布式锁功能。 +- **Map treeCacheMap**:树缓存映射,用于缓存ZooKeeper节点的子节点信息。 + +`ZooKeeperRegistry`的初始化过程包括: +1. 从配置中获取ZooKeeper服务器列表。 +2. 创建ZooKeeper客户端并连接到ZooKeeper集群。 +3. 注册当前服务器信息到ZooKeeper。 +4. 初始化树缓存用于监听节点变更。 + +```mermaid +classDiagram +class ZooKeeperRegistry { +-InterProcessMutex mutex +-CuratorFramework client +-Map treeCacheMap +-Properties properties ++init(Properties properties) ++acquire(String key, long timeout) ++release(String key) ++subscribe(String key, SubscribeListener listener) ++unSubscribe(String key) ++addConnectionListener(ConnectionListener connectionListener) ++getActiveServerList() ++close() +} +class Registry { +<> ++init(Properties properties) ++acquire(String key, long timeout) ++release(String key) ++subscribe(String key, SubscribeListener listener) ++unSubscribe(String key) ++addConnectionListener(ConnectionListener connectionListener) ++getActiveServerList() ++close() +} +ZooKeeperRegistry --|> Registry : 实现 +``` + +**本节分析的具体源文件:** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) + +## MySQL注册中心实现 + +MySQL注册中心实现位于`io.datavines.registry.plugin.MysqlRegistry`类中。该实现利用JDBC与MySQL数据库进行交互。 + +`MysqlRegistry`类的主要组件包括: +- **MysqlMutex mysqlMutex**:MySQL分布式锁管理器。 +- **MysqlServerStateManager mysqlServerStateManager**:MySQL服务器状态管理器。 + +`MysqlRegistry`的初始化过程包括: +1. 从配置中获取MySQL连接信息。 +2. 建立与MySQL数据库的连接。 +3. 初始化`MysqlMutex`和`MysqlServerStateManager`实例。 + +```mermaid +classDiagram +class MysqlRegistry { +-MysqlMutex mysqlMutex +-MysqlServerStateManager mysqlServerStateManager ++init(Properties properties) ++acquire(String key, long timeout) ++release(String key) ++subscribe(String key, SubscribeListener listener) ++unSubscribe(String key) ++addConnectionListener(ConnectionListener connectionListener) ++getActiveServerList() ++close() +} +class Registry { +<> ++init(Properties properties) ++acquire(String key, long timeout) ++release(String key) ++subscribe(String key, SubscribeListener listener) ++unSubscribe(String key) ++addConnectionListener(ConnectionListener connectionListener) ++getActiveServerList() ++close() +} +MysqlRegistry --|> Registry : 实现 +``` + +**本节分析的具体源文件:** +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) + +## 分布式锁实现 + +DataVines的分布式锁实现通过`acquire`和`release`方法提供。不同的注册中心插件有不同的实现方式。 + +在ZooKeeper注册中心中,分布式锁通过Curator的`InterProcessMutex`实现。`InterProcessMutex`利用ZooKeeper的临时顺序节点来实现公平的分布式锁。 + +在MySQL注册中心中,分布式锁通过`MysqlMutex`类实现。`MysqlMutex`利用MySQL的行级锁和`dv_registry_lock`表来实现分布式锁。 + +`MysqlMutex`的主要特性包括: +- **锁获取**:通过`INSERT`语句尝试插入锁记录,如果主键冲突则表示锁已被占用。 +- **锁释放**:通过`DELETE`语句删除锁记录。 +- **锁续期**:通过后台线程定期更新锁的更新时间来续期。 +- **过期清理**:定期清理超过一定时间未更新的锁记录。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant MysqlMutex as "MysqlMutex" +participant DB as "MySQL数据库" +Client->>MysqlMutex : acquire("lock_key", 30) +MysqlMutex->>DB : INSERT INTO dv_registry_lock (lock_key, lock_owner, update_time) +alt 锁获取成功 +DB-->>MysqlMutex : 插入成功 +MysqlMutex-->>Client : true +else 锁已被占用 +DB-->>MysqlMutex : 主键冲突异常 +MysqlMutex->>MysqlMutex : 休眠1秒后重试 +MysqlMutex->>DB : 再次尝试INSERT +DB-->>MysqlMutex : 插入成功 +MysqlMutex-->>Client : true +end +Client->>MysqlMutex : release("lock_key") +MysqlMutex->>DB : DELETE FROM dv_registry_lock WHERE lock_key = "lock_key" +DB-->>MysqlMutex : 删除成功 +MysqlMutex-->>Client : true +``` + +**本节分析的具体源文件:** +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java) + +## 服务器状态管理 + +服务器状态管理是注册中心的核心功能之一,用于维护集群中所有服务器的活跃状态。 + +在ZooKeeper注册中心中,服务器状态通过ZooKeeper的临时节点实现。当服务器连接到ZooKeeper时,创建一个临时节点;当服务器断开连接时,ZooKeeper会自动删除该节点。 + +在MySQL注册中心中,服务器状态通过`MysqlServerStateManager`类管理。`MysqlServerStateManager`的主要功能包括: +- **心跳机制**:通过`HeartBeater`线程定期更新服务器的心跳时间。 +- **服务器检查**:通过`ServerChecker`线程定期检查其他服务器的心跳状态。 +- **状态变更通知**:当检测到服务器状态变更时,通过`SubscribeListener`通知监听器。 + +```mermaid +classDiagram +class MysqlServerStateManager { +-Connection connection +-ConcurrentHashMap liveServerMap +-Set deadServers +-SubscribeListener subscribeListener +-ServerInfo serverInfo +-Properties properties ++registry(SubscribeListener subscribeListener) ++unRegistry() ++refreshServer() ++getActiveServerList() ++close() +} +class HeartBeater { ++run() +} +class ServerChecker { ++run() +} +MysqlServerStateManager --> HeartBeater : 包含 +MysqlServerStateManager --> ServerChecker : 包含 +``` + +**本节分析的具体源文件:** +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java) + +## 连接状态监听与事件通知 + +连接状态监听与事件通知机制允许应用程序对注册中心的连接状态变化做出响应。 + +`ConnectionListener`接口定义了连接状态变更的回调方法。当注册中心的连接状态发生变化时(如连接、重连、断开连接),会调用`onUpdate`方法。 + +`SubscribeListener`接口定义了数据变更的回调方法。当注册中心中特定键的数据发生变化时,会调用`notify`方法。 + +在ZooKeeper注册中心中,连接状态监听通过Curator的`ConnectionStateListener`实现。事件通知通过`TreeCache`实现,当监听的节点发生变化时,会触发相应的事件。 + +在MySQL注册中心中,连接状态监听目前为空实现,因为MySQL的连接状态管理由JDBC驱动处理。事件通知通过轮询`dv_server`表实现。 + +```mermaid +classDiagram +class ConnectionListener { +<> ++onUpdate(ConnectionStatus status) +} +class SubscribeListener { +<> ++notify(Event event) +} +class Event { +-String key +-String value +-Type type ++EventBuilder builder() +} +class ConnectionStatus { +<> +CONNECTED +RECONNECTED +DISCONNECTED +} +class Event$Type { +<> +ADD +UPDATE +REMOVE +} +SubscribeListener --> Event : 接收 +Event --> Event$Type : 包含 +``` + +**本节分析的具体源文件:** +- [ConnectionListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\SubscribeListener.java) +- [Event.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Event.java) +- [ConnectionStatus.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionStatus.java) + +## 性能优化建议 + +在开发注册中心插件时,需要考虑以下性能优化建议: + +1. **连接池**:对于数据库类型的注册中心,使用连接池来管理数据库连接,避免频繁创建和销毁连接的开销。 +2. **缓存**:对于频繁读取的数据,使用本地缓存来减少对注册中心的访问次数。 +3. **批量操作**:对于需要批量处理的操作,尽量使用批量API来减少网络往返次数。 +4. **异步处理**:对于耗时的操作,使用异步处理来避免阻塞主线程。 +5. **连接复用**:保持注册中心连接的长连接,避免频繁的连接和断开操作。 + +在MySQL注册中心实现中,已经通过`ScheduledExecutorService`实现了心跳和服务器检查的异步处理,这是一个良好的性能优化实践。 + +**本节不分析具体源文件,因此不提供源引用。** + +## 高可用性设计考虑 + +高可用性是注册中心设计的关键考虑因素。以下是一些高可用性设计建议: + +1. **集群部署**:注册中心本身应该以集群模式部署,避免单点故障。 +2. **故障转移**:当主节点故障时,能够快速切换到备用节点。 +3. **数据一致性**:确保在分布式环境下数据的一致性。 +4. **网络分区处理**:在网络分区情况下,能够正确处理脑裂问题。 +5. **监控和告警**:提供完善的监控和告警机制,及时发现和处理问题。 + +在ZooKeeper注册中心中,ZooKeeper本身就是一个高可用的分布式协调服务,天然支持集群部署和故障转移。在MySQL注册中心中,可以通过MySQL的主从复制或集群模式来实现高可用性。 + +**本节不分析具体源文件,因此不提供源引用。** \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/ER\345\233\276.md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/ER\345\233\276.md" new file mode 100644 index 00000000..b4bed100 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/ER\345\233\276.md" @@ -0,0 +1,436 @@ +# ER图 + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java) +- [Job.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java) +- [Workspace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Workspace.java) +- [UserWorkspace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/UserWorkspace.java) +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) +- [CatalogEntityTagRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityTagRel.java) +- [JobSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java) +- [JobExecutionResult.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java) +- [JobQualityReport.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobQualityReport.java) +- [Sla.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Sla.java) +- [SlaJob.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/SlaJob.java) +- [ErrorDataStorage.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/ErrorDataStorage.java) +- [Config.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Config.java) +- [dv_job](file://scripts/sql/datavines-mysql.sql#L499-L534) +- [dv_job_execution](file://scripts/sql/datavines-mysql.sql#L539-L580) +- [dv_datasource](file://scripts/sql/datavines-mysql.sql#L417-L432) +- [dv_workspace](file://scripts/sql/datavines-mysql.sql#L824-L834) +- [dv_user_workspace](file://scripts/sql/datavines-mysql.sql#L808-L819) +- [dv_user](file://scripts/sql/datavines-mysql.sql#L791-L803) +- [dv_catalog_entity_instance](file://scripts/sql/datavines-mysql.sql#L213-L233) +- [dv_catalog_entity_rel](file://scripts/sql/datavines-mysql.sql#L271-L282) +- [dv_catalog_entity_tag_rel](file://scripts/sql/datavines-mysql.sql#L287-L299) +- [dv_job_schedule](file://scripts/sql/datavines-mysql.sql#L660-L675) +- [dv_job_execution_result](file://scripts/sql/datavines-mysql.sql#L585-L608) +- [dv_job_quality_report](file://scripts/sql/datavines-mysql.sql#L614-L626) +- [dv_sla](file://scripts/sql/datavines-mysql.sql#L708-L718) +- [dv_sla_job](file://scripts/sql/datavines-mysql.sql#L724-L735) +- [dv_error_data_storage](file://scripts/sql/datavines-mysql.sql#L468-L481) +- [dv_config](file://scripts/sql/datavines-mysql.sql#L839-L851) + + +## 目录 +1. [简介](#简介) +2. [核心实体与属性](#核心实体与属性) +3. [实体关系图(ER图)](#实体关系图er图) +4. [关键关系设计说明](#关键关系设计说明) +5. [核心业务流程数据流](#核心业务流程数据流) +6. [附录:表结构详情](#附录表结构详情) + +## 简介 +本文档旨在为DataVines数据库提供一份全面的实体关系图(ER图)文档。DataVines是一个数据质量平台,其数据库设计围绕数据源、数据质量任务、执行记录、用户和工作空间等核心概念展开。本ER图文档将清晰地展示这些核心表之间的关系,标注主要属性、主键、外键约束和基数。同时,文档将解释关键关系的设计决策,并突出显示从数据源配置到任务执行的完整数据流路径。 + +## 核心实体与属性 +DataVines数据库的核心实体包括数据源、任务、执行记录、用户、工作空间等。以下是各核心实体的主要属性和主键。 + +### 数据源 (dv_datasource) +数据源实体存储了所有连接到外部数据库或数据存储的配置信息。 +- **主键**: `id` +- **主要属性**: + - `uuid`: 数据源的唯一标识符 + - `name`: 数据源名称 + - `type`: 数据源类型(如MySQL, PostgreSQL, Hive等) + - `param`: 数据源连接参数(JSON格式,包含主机、端口、数据库名、用户名、密码等) + - `workspace_id`: 所属工作空间ID(外键) + - `create_by`: 创建者用户ID(外键) + +### 任务 (dv_job) +任务实体定义了数据质量检查的规则和配置。 +- **主键**: `id` +- **主要属性**: + - `name`: 任务名称 + - `type`: 任务类型(如数据质量检查、元数据抓取等) + - `datasource_id`: 关联的数据源ID(外键) + - `schema_name`, `table_name`, `column_name`: 指定检查的数据库、表和列 + - `metric_type`: 规则类型(如行数检查、空值检查等) + - `parameter`: 任务的详细参数(JSON格式) + - `create_by`: 创建者用户ID(外键) + +### 任务执行记录 (dv_job_execution) +任务执行记录实体存储了每次任务运行的实例信息和状态。 +- **主键**: `id` +- **主要属性**: + - `name`: 执行实例名称 + - `job_id`: 关联的任务ID(外键) + - `status`: 执行状态(如成功、失败、运行中) + - `submit_time`, `start_time`, `end_time`: 提交、开始和结束时间 + - `execute_host`: 执行主机 + - `parameter`: 运行时参数 + - `log_path`: 日志文件路径 + +### 用户 (dv_user) +用户实体存储了系统用户的账户信息。 +- **主键**: `id` +- **主要属性**: + - `username`: 用户名 + - `password`: 加密后的密码 + - `email`: 邮箱 + - `admin`: 是否为管理员 + +### 工作空间 (dv_workspace) +工作空间实体是组织和隔离用户、数据源、任务等资源的逻辑单元。 +- **主键**: `id` +- **主要属性**: + - `name`: 工作空间名称 + - `create_by`: 创建者用户ID(外键) + +### 用户-工作空间关联 (dv_user_workspace) +该实体是用户和工作空间之间的多对多关系的关联表。 +- **主键**: `id` +- **主要属性**: + - `user_id`: 用户ID(外键) + - `workspace_id`: 工作空间ID(外键) + - `role_id`: 用户在该工作空间中的角色ID + +### 数据目录实体实例 (dv_catalog_entity_instance) +该实体存储了从数据源中抓取的元数据实例,如数据库、表、列等。 +- **主键**: `id` +- **主要属性**: + - `uuid`: 实体实例的唯一标识符 + - `type`: 实体类型(如DATABASE, TABLE, COLUMN) + - `datasource_id`: 所属数据源ID(外键) + - `fully_qualified_name`: 全限定名(如`database.table.column`) + - `display_name`: 展示名称 + - `properties`: 其他属性(JSON格式) + +## 实体关系图(ER图) + +```mermaid +erDiagram +dv_user ||--o{ dv_user_workspace : "创建/属于" +dv_workspace ||--o{ dv_user_workspace : "包含" +dv_workspace ||--o{ dv_datasource : "包含" +dv_workspace ||--o{ dv_sla : "包含" +dv_workspace ||--o{ dv_error_data_storage : "包含" +dv_workspace ||--o{ dv_config : "包含" +dv_user ||--o{ dv_access_token : "拥有" +dv_user ||--o{ dv_tenant : "拥有" +dv_datasource ||--o{ dv_job : "配置" +dv_datasource ||--o{ dv_catalog_entity_instance : "包含" +dv_job ||--o{ dv_job_schedule : "拥有" +dv_job ||--o{ dv_job_execution : "生成" +dv_job ||--o{ dv_sla_job : "关联" +dv_job ||--o{ dv_job_issue_rel : "触发" +dv_job_execution ||--o{ dv_job_execution_result : "产生" +dv_job_execution ||--o{ dv_command : "接收" +dv_job_execution_result ||--o{ dv_job_execution_result_report_rel : "关联" +dv_job_quality_report ||--o{ dv_job_execution_result_report_rel : "包含" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_profile : "拥有" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_rel : "作为实体1" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_rel : "作为实体2" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_tag_rel : "被标记" +dv_catalog_tag ||--o{ dv_catalog_entity_tag_rel : "标记" +dv_catalog_tag_category ||--o{ dv_catalog_tag : "分类" +dv_sla ||--o{ dv_sla_job : "管理" +dv_sla ||--o{ dv_sla_notification : "通知" +dv_sla ||--o{ dv_sla_sender : "发送" +dv_error_data_storage ||--o{ dv_job : "作为错误存储" +dv_user { +bigint id PK +varchar username UK +varchar password +varchar email +tinyint admin +datetime create_time +datetime update_time +} +dv_workspace { +bigint id PK +varchar name UK +bigint create_by FK +datetime create_time +datetime update_time +} +dv_user_workspace { +bigint id PK +bigint user_id FK +bigint workspace_id FK +bigint role_id FK +bigint create_by FK +datetime create_time +datetime update_time +} +dv_datasource { +bigint id PK +varchar uuid UK +varchar name +varchar type +text param +bigint workspace_id FK +bigint create_by FK +datetime create_time +datetime update_time +} +dv_job { +bigint id PK +varchar name +int type +bigint datasource_id FK +varchar schema_name +varchar table_name +varchar column_name +varchar metric_type +text parameter +bigint create_by FK +datetime create_time +datetime update_time +} +dv_job_schedule { +bigint id PK +varchar type +text param +bigint job_id FK +varchar cron_expression +tinyint status +datetime start_time +datetime end_time +bigint create_by FK +datetime create_time +datetime update_time +} +dv_job_execution { +bigint id PK +varchar name +bigint job_id FK +int job_type +varchar schema_name +varchar table_name +varchar column_name +varchar metric_type +bigint datasource_id FK +int status +datetime submit_time +datetime schedule_time +datetime start_time +datetime end_time +datetime create_time +datetime update_time +} +dv_job_execution_result { +bigint id PK +bigint job_execution_id FK +varchar metric_unique_key +varchar metric_type +decimal actual_value +decimal expected_value +int state +datetime create_time +datetime update_time +} +dv_job_quality_report { +bigint id PK +bigint datasource_id FK +varchar entity_level +varchar database_name +varchar table_name +varchar column_name +decimal score +date report_date +datetime create_time +datetime update_time +} +dv_job_execution_result_report_rel { +bigint id PK +bigint quality_report_id FK +bigint job_execution_result_id FK +datetime create_time +datetime update_time +} +dv_catalog_entity_instance { +bigint id PK +varchar uuid UK +varchar type +bigint datasource_id FK +varchar fully_qualified_name UK +varchar display_name +text properties +varchar status +datetime create_time +datetime update_time +} +dv_catalog_entity_rel { +bigint id PK +varchar entity1_uuid FK +varchar entity2_uuid FK +varchar type +datetime update_time +} +dv_catalog_entity_tag_rel { +bigint id PK +varchar entity_uuid FK +varchar tag_uuid FK +bigint create_by FK +datetime create_time +datetime update_time +} +dv_catalog_tag { +bigint id PK +varchar uuid UK +varchar category_uuid FK +varchar name +bigint create_by FK +datetime create_time +datetime update_time +} +dv_catalog_tag_category { +bigint id PK +varchar uuid UK +varchar name +bigint workspace_id FK +bigint create_by FK +datetime create_time +datetime update_time +} +dv_sla { +bigint id PK +bigint workspace_id FK +varchar name +varchar description +bigint create_by FK +datetime create_time +datetime update_time +} +dv_sla_job { +bigint id PK +bigint workspace_id FK +bigint sla_id FK +bigint job_id FK +bigint create_by FK +datetime create_time +datetime update_time +} +dv_error_data_storage { +bigint id PK +varchar name +varchar type +text param +bigint workspace_id FK +bigint create_by FK +datetime create_time +datetime update_time +} +dv_config { +bigint id PK +bigint workspace_id FK +varchar var_key +text var_value +tinyint is_default +bigint create_by FK +datetime create_time +datetime update_time +} +``` + +**图源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +## 关键关系设计说明 +DataVines的数据库设计采用了多种关系模式来满足其复杂的业务需求。 + +### 一对多关系 (1:N) +这是最常见的一种关系。例如: +- **工作空间与数据源**: 一个工作空间可以包含多个数据源,但一个数据源只能属于一个工作空间。这通过在`dv_datasource`表中设置`workspace_id`作为外键来实现。 +- **任务与执行记录**: 一个任务可以被多次执行,每次执行生成一条执行记录。这通过在`dv_job_execution`表中设置`job_id`作为外键来实现。 +- **数据源与元数据实例**: 一个数据源可以包含多个数据库、表、列等元数据实例。这通过在`dv_catalog_entity_instance`表中设置`datasource_id`作为外键来实现。 + +### 多对多关系 (M:N) +当两个实体之间存在多对多关系时,需要引入一个关联表(也称为连接表或桥接表)来实现。 +- **用户与工作空间**: 一个用户可以加入多个工作空间,一个工作空间也可以有多个用户。这种关系通过`dv_user_workspace`关联表实现,该表包含`user_id`和`workspace_id`两个外键。 +- **元数据实例与标签**: 一个元数据实例(如一张表)可以被多个标签标记,一个标签也可以应用于多个元数据实例。这种关系通过`dv_catalog_entity_tag_rel`关联表实现,该表包含`entity_uuid`和`tag_uuid`两个外键。 +- **SLA与任务**: 一个SLA规则可以管理多个任务,一个任务也可以被多个SLA规则管理。这种关系通过`dv_sla_job`关联表实现。 + +### 实体间关系 (dv_catalog_entity_rel) +`dv_catalog_entity_rel`表是一个特殊的设计,用于描述元数据实体之间的各种关系,如上下游、父子等。它通过`entity1_uuid`和`entity2_uuid`两个字段指向`dv_catalog_entity_instance`表的`uuid`,并通过`type`字段定义关系类型(如`upstream`, `downstream`)。这种设计非常灵活,能够表示复杂的元数据血缘和依赖关系。 + +## 核心业务流程数据流 +以下是从数据源配置到任务执行的完整数据流路径,在ER图中已用粗线标出: + +1. **数据源配置**: 用户首先在某个`工作空间 (dv_workspace)`中创建一个`数据源 (dv_datasource)`。 +2. **元数据抓取**: 系统会根据数据源配置,自动抓取其元数据,并存储为`元数据实例 (dv_catalog_entity_instance)`。 +3. **任务创建**: 用户基于已有的数据源和元数据实例,创建一个`任务 (dv_job)`。 +4. **任务调度**: 为任务配置`任务调度 (dv_job_schedule)`,使其可以周期性执行。 +5. **任务执行**: 调度器触发任务执行,生成一条`任务执行记录 (dv_job_execution)`。 +6. **结果生成**: 任务执行完成后,会生成`任务执行结果 (dv_job_execution_result)`。 +7. **报告生成**: 系统会将执行结果汇总,生成`数据质量报告 (dv_job_quality_report)`。 + +## 附录:表结构详情 +本节提供核心表的详细结构,包括字段名、数据类型、约束和注释。 + +### dv_datasource (数据源表) +| 字段名 | 类型 | 约束 | 注释 | +| :--- | :--- | :--- | :--- | +| id | bigint(20) | PRIMARY KEY, AUTO_INCREMENT | 主键 | +| uuid | varchar(64) | NOT NULL, UNIQUE | 数据源UUID | +| name | varchar(255) | NOT NULL, UNIQUE | 数据源名称 | +| type | varchar(255) | NOT NULL | 数据源类型 | +| param | text | NOT NULL | 数据源参数 | +| workspace_id | bigint(20) | NOT NULL | 工作空间ID | +| create_by | bigint(20) | NOT NULL | 创建用户ID | +| create_time | datetime | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 | +| update_by | bigint(20) | NOT NULL | 更新用户ID | +| update_time | datetime | NOT NULL, ON UPDATE CURRENT_TIMESTAMP | 更新时间 | + +### dv_job (任务表) +| 字段名 | 类型 | 约束 | 注释 | +| :--- | :--- | :--- | :--- | +| id | bigint(20) | PRIMARY KEY, AUTO_INCREMENT | 主键 | +| name | varchar(255) | DEFAULT NULL | 作业名称 | +| type | int(11) | NOT NULL, DEFAULT '0' | 作业类型 | +| datasource_id | bigint(20) | NOT NULL | 数据源ID | +| schema_name | varchar(128) | DEFAULT NULL | 数据库名 | +| table_name | varchar(128) | DEFAULT NULL | 表名 | +| column_name | varchar(128) | DEFAULT NULL | 列名 | +| metric_type | varchar(255) | DEFAULT NULL | 规则类型 | +| parameter | longtext | DEFAULT NULL | 作业参数 | +| create_by | bigint(20) | NOT NULL | 创建用户ID | +| create_time | datetime | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 | +| update_by | bigint(20) | NOT NULL | 更新用户ID | +| update_time | datetime | NOT NULL, ON UPDATE CURRENT_TIMESTAMP | 更新时间 | + +### dv_job_execution (任务执行记录表) +| 字段名 | 类型 | 约束 | 注释 | +| :--- | :--- | :--- | :--- | +| id | bigint(20) | PRIMARY KEY, AUTO_INCREMENT | 主键 | +| name | varchar(255) | NOT NULL | 作业运行实例名称 | +| job_id | bigint(20) | NOT NULL | 作业ID | +| status | int(11) | DEFAULT NULL | 作业运行状态 | +| submit_time | datetime | DEFAULT NULL | 提交时间 | +| schedule_time | datetime | DEFAULT NULL | 调度时间 | +| start_time | datetime | DEFAULT NULL | 开始时间 | +| end_time | datetime | DEFAULT NULL | 结束时间 | +| create_time | datetime | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 | +| update_time | datetime | NOT NULL, ON UPDATE CURRENT_TIMESTAMP | 更新时间 | + +**图源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +**节源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\346\200\247\350\203\275\344\274\230\345\214\226.md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\346\200\247\350\203\275\344\274\230\345\214\226.md" new file mode 100644 index 00000000..7bcc3e60 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\346\200\247\350\203\275\344\274\230\345\214\226.md" @@ -0,0 +1,235 @@ +# 性能优化 + + +**本文档引用的文件** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [JobExecutionMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobExecutionMapper.java) +- [JdbcDataSourceInfoManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceInfoManager.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [DefaultDataSourceInfoUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/DefaultDataSourceInfoUtils.java) +- [TableColumnInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/entity/TableColumnInfo.java) +- [SqlUtils.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/utils/SqlUtils.java) + + +## 目录 +1. [引言](#引言) +2. [数据库性能瓶颈分析](#数据库性能瓶颈分析) +3. [SQL查询优化建议](#sql查询优化建议) +4. [数据库配置调优](#数据库配置调优) +5. [分库分表策略建议](#分库分表策略建议) +6. [数据库性能监控](#数据库性能监控) +7. [定期维护任务清单](#定期维护任务清单) +8. [结论](#结论) + +## 引言 + +DataVines是一个数据质量监控平台,其核心功能包括数据源管理、任务执行记录查询和大规模数据处理。随着数据量的增长,数据库性能成为影响系统整体效率的关键因素。本文档旨在为数据库管理员提供一套全面的性能优化指南,涵盖SQL查询优化、数据库配置调优、分库分表策略以及定期维护任务等方面。 + +**本文档引用的文件** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java#L1-L144) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) + +## 数据库性能瓶颈分析 + +DataVines在处理大规模数据源管理和任务执行记录查询时,可能会遇到以下常见的数据库瓶颈: + +1. **任务执行记录查询性能下降**:随着任务执行记录的积累,`dv_job_execution`表的数据量会迅速增长,导致查询性能下降。 +2. **大规模数据源管理开销大**:当系统管理的数据源数量较多时,元数据抓取和管理的开销会显著增加。 +3. **连接池资源竞争**:高并发场景下,数据库连接池可能成为性能瓶颈,导致连接获取延迟增加。 + +通过分析`JobExecutionMapper.xml`中的SQL语句,可以发现任务执行记录查询涉及多个条件过滤和排序操作,这些操作在大数据量下可能导致性能问题。 + +```mermaid +graph TD +A[任务执行记录查询] --> B[条件过滤] +B --> C[按更新时间排序] +C --> D[分页返回结果] +E[大规模数据源管理] --> F[元数据抓取] +F --> G[实体关系维护] +G --> H[标签关联管理] +``` + +**图表来源** +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml#L1-L156) + +**本节来源** +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml#L1-L156) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L166-L177) + +## SQL查询优化建议 + +针对DataVines中的常见查询场景,提出以下SQL查询优化建议: + +### 查询重写 + +对于复杂的查询条件,可以通过查询重写来提高性能。例如,在`getJobExecutionPage`查询中,可以将多个`LIKE`操作合并为一个正则表达式匹配,减少查询解析时间。 + +```sql +-- 原始查询 +SELECT * FROM dv_job_execution +WHERE LOWER(name) LIKE '%searchVal%' + AND LOWER(schema_name) LIKE '%schemaSearch%' + AND LOWER(table_name) LIKE '%tableSearch%'; + +-- 优化后查询 +SELECT * FROM dv_job_execution +WHERE name REGEXP '.*searchVal.*' + AND schema_name REGEXP '.*schemaSearch.*' + AND table_name REGEXP '.*tableSearch.*'; +``` + +### 连接优化 + +在涉及多表连接的查询中,应确保连接字段上有适当的索引。例如,在`dv_catalog_entity_rel`表中,`entity1_uuid`和`entity2_uuid`字段上已经建立了唯一索引,这有助于提高连接性能。 + +### 子查询优化 + +避免在WHERE子句中使用子查询,因为这可能导致全表扫描。可以将子查询转换为JOIN操作,利用索引提高查询效率。 + +```sql +-- 避免使用子查询 +SELECT * FROM dv_job_execution +WHERE job_id IN (SELECT job_id FROM dv_job WHERE status = 'active'); + +-- 推荐使用JOIN +SELECT je.* FROM dv_job_execution je +JOIN dv_job j ON je.job_id = j.job_id +WHERE j.status = 'active'; +``` + +**本节来源** +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml#L111-L130) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L280-L282) + +## 数据库配置调优 + +### 连接池大小 + +根据`application.yaml`中的配置,HikariCP连接池的最大池大小设置为50。对于高并发场景,可以根据实际负载调整此值。建议通过压力测试确定最优的连接池大小。 + +```yaml +spring: + datasource: + hikari: + maximum-pool-size: 50 +``` + +### 查询缓存 + +启用查询缓存可以显著提高重复查询的性能。对于不经常变化的数据,如元数据信息,可以考虑使用缓存机制。 + +### 其他调优参数 + +- **最小空闲连接数**:设置为5,确保有足够的空闲连接供快速响应。 +- **连接超时时间**:设置为30秒,防止长时间等待连接。 +- **空闲超时时间**:设置为10分钟,及时释放空闲连接。 + +```yaml +spring: + datasource: + hikari: + minimum-idle: 5 + connection-timeout: 30000 + idle-timeout: 600000 +``` + +**本节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L23-L38) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java#L59-L60) + +## 分库分表策略建议 + +针对大规模部署场景,建议采用分库分表策略来分散数据存储和查询压力。 + +### 水平分表 + +根据时间维度对`dv_job_execution`表进行水平分表,例如按月或按周创建子表。这样可以减少单个表的数据量,提高查询性能。 + +```sql +-- 按月分表 +CREATE TABLE dv_job_execution_2023_01 LIKE dv_job_execution; +CREATE TABLE dv_job_execution_2023_02 LIKE dv_job_execution; +``` + +### 垂直分库 + +将不同类型的业务数据存储在不同的数据库中,例如将任务执行记录与元数据信息分开存储,减少单个数据库的负载。 + +### 分片键选择 + +选择合适的分片键是分库分表成功的关键。对于任务执行记录,可以选择`job_id`或`create_time`作为分片键,确保数据均匀分布。 + +```mermaid +graph TD +A[原始表] --> B[分片键选择] +B --> C[水平分表] +C --> D[按时间分片] +C --> E[按ID分片] +B --> F[垂直分库] +F --> G[任务执行库] +F --> H[元数据库] +``` + +**图表来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L166-L177) + +**本节来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L166-L177) +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml#L111-L130) + +## 数据库性能监控 + +### 关键指标 + +监控以下关键性能指标,及时发现和解决性能问题: + +- **查询响应时间**:监控SQL查询的平均响应时间和最大响应时间。 +- **连接池使用率**:监控连接池的活跃连接数和等待连接数。 +- **慢查询日志**:定期分析慢查询日志,找出性能瓶颈。 + +### 工具建议 + +使用Prometheus和Grafana搭建监控系统,实时监控数据库性能指标。结合Spring Boot Actuator暴露的端点,收集应用层面的性能数据。 + +```mermaid +graph TD +A[数据库] --> B[Prometheus] +B --> C[Grafana] +D[应用] --> B +C --> E[报警] +``` + +**图表来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L72-L80) + +**本节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L72-L80) +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml#L111-L130) + +## 定期维护任务清单 + +为数据库管理员提供以下定期维护任务清单: + +1. **更新统计信息**:定期更新表的统计信息,帮助查询优化器生成更优的执行计划。 +2. **碎片整理**:定期对表进行碎片整理,提高存储效率和查询性能。 +3. **索引优化**:定期检查和优化索引,删除无用索引,添加缺失索引。 +4. **备份与恢复测试**:定期执行数据库备份,并测试恢复流程,确保数据安全。 + +```sql +-- 更新统计信息 +ANALYZE TABLE dv_job_execution; + +-- 碎片整理 +OPTIMIZE TABLE dv_job_execution; +``` + +**本节来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L166-L177) +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml#L111-L130) + +## 结论 + +通过对DataVines的数据库性能瓶颈进行分析,本文档提供了全面的优化建议,包括SQL查询优化、数据库配置调优、分库分表策略和定期维护任务。实施这些优化措施可以显著提高系统的整体性能和稳定性,为大规模数据处理提供有力支持。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241.md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241.md" new file mode 100644 index 00000000..c4ffdf76 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241.md" @@ -0,0 +1,253 @@ +# 数据库设计 + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) +- [JobExecutionResult.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java) +- [Config.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Config.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录)(如有必要) + +## 引言 +DataVines是一个数据质量监控和元数据管理平台,其数据库设计是整个系统的核心。数据库模式支持数据质量规则的定义、执行、结果存储以及元数据的管理。系统使用MySQL或PostgreSQL作为后端数据库,通过MyBatis-Plus进行ORM映射。数据库设计围绕工作空间(Workspace)、数据源(DataSource)、数据质量作业(Job)和执行实例(JobExecution)等核心概念展开。此外,系统还集成了Quartz调度框架来管理作业的定时执行。本设计文档将详细描述DataVines的数据库模式,包括实体关系、表结构、索引策略和性能优化建议。 + +## 项目结构 +DataVines的项目结构清晰地划分了不同的功能模块。核心的数据库表定义位于`scripts/sql/datavines-mysql.sql`文件中,该文件包含了所有表的创建语句。实体类(Entity)位于`datavines-server/src/main/java/io/datavines/server/repository/entity/`目录下,这些类使用MyBatis-Plus注解与数据库表进行映射。配置文件`application.yaml`定义了数据库连接信息和Quartz调度器的配置。这种分层结构使得数据库设计与业务逻辑分离,便于维护和扩展。 + +```mermaid +erDiagram +dv_workspace ||--o{ dv_user_workspace : "包含" +dv_user ||--o{ dv_user_workspace : "属于" +dv_workspace ||--o{ dv_datasource : "包含" +dv_workspace ||--o{ dv_env : "包含" +dv_workspace ||--o{ dv_sla : "包含" +dv_workspace ||--o{ dv_tenant : "包含" +dv_datasource ||--o{ dv_job : "关联" +dv_job ||--o{ dv_job_schedule : "拥有" +dv_job ||--o{ dv_job_execution : "生成" +dv_job_execution ||--o{ dv_job_execution_result : "包含" +dv_job_execution_result ||--o{ dv_actual_values : "存储" +dv_job_execution ||--o{ dv_command : "接收" +dv_job ||--o{ dv_job_issue_rel : "产生" +dv_issue ||--o{ dv_job_issue_rel : "被关联" +dv_sla ||--o{ dv_sla_job : "管理" +dv_job ||--o{ dv_sla_job : "被管理" +dv_sla ||--o{ dv_sla_notification : "发送" +dv_sla_sender ||--o{ dv_sla_notification : "通过" +dv_catalog_entity_definition ||--o{ dv_catalog_entity_instance : "实例化" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_profile : "包含" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_rel : "关联" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_tag_rel : "标记" +dv_catalog_tag_category ||--o{ dv_catalog_tag : "分类" +dv_catalog_tag ||--o{ dv_catalog_entity_tag_rel : "标记" +QRTZ_JOB_DETAILS ||--o{ QRTZ_TRIGGERS : "触发" +QRTZ_TRIGGERS ||--o{ QRTZ_CRON_TRIGGERS : "使用" +dv_job ||--o{ QRTZ_JOB_DETAILS : "对应" +dv_job_schedule ||--o{ QRTZ_TRIGGERS : "对应" +``` + +**图表来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +**章节来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +## 核心组件 +DataVines的核心组件围绕数据质量监控和元数据管理展开。`dv_job`表是数据质量规则的定义中心,存储了规则的类型、参数和执行引擎等信息。`dv_job_execution`表记录了每次规则执行的实例,是系统运行时状态的核心。`dv_job_execution_result`表存储了规则执行后的具体结果,包括实际值、期望值和比较结果。元数据管理部分以`dv_catalog_entity_instance`表为核心,代表了数据源中的数据库、表、列等实体。`dv_workspace`和`dv_user`表则构成了系统的多租户和权限管理基础。这些组件通过外键和关联表紧密联系,形成了一个完整的数据治理体系。 + +**章节来源** +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) +- [JobExecutionResult.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java) + +## 架构概述 +DataVines的系统架构采用微服务设计,数据库作为持久化层,为上层应用提供数据支持。应用层通过MyBatis-Plus访问数据库,执行CRUD操作。Quartz调度框架负责作业的定时触发,其调度信息存储在`QRTZ_*`系列表中。数据质量作业的定义和调度信息存储在`dv_job`和`dv_job_schedule`表中,当作业被触发时,系统会创建`dv_job_execution`实例来跟踪执行过程。执行结果被详细记录在`dv_job_execution_result`和`dv_actual_values`表中。元数据管理模块独立运行,通过`dv_catalog_*`系列表存储和管理数据资产的元信息。整个架构通过清晰的模块划分和数据库设计,实现了高内聚、低耦合。 + +```mermaid +graph TB +subgraph "前端 UI" +UI[Web 界面] +end +subgraph "应用服务层" +API[API Server] +Scheduler[Quartz 调度器] +end +subgraph "持久化层" +DB[(MySQL/PostgreSQL)] +end +UI --> API +API --> DB +Scheduler --> DB +``` + +**图表来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 详细组件分析 + +### 数据质量作业分析 +数据质量作业是DataVines的核心功能,其设计围绕`dv_job`、`dv_job_execution`和`dv_job_execution_result`三个主要表展开。 + +#### 数据质量作业实体关系图 +```mermaid +erDiagram +dv_job ||--o{ dv_job_schedule : "拥有" +dv_job ||--o{ dv_job_execution : "生成" +dv_job_execution ||--o{ dv_job_execution_result : "包含" +dv_job_execution ||--o{ dv_command : "接收" +dv_job ||--o{ dv_job_issue_rel : "产生" +dv_issue ||--o{ dv_job_issue_rel : "被关联" +``` + +**图表来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L497-L656) + +#### 数据质量作业执行流程序列图 +```mermaid +sequenceDiagram +participant Scheduler as "Quartz 调度器" +participant API as "API Server" +participant JobExecution as "dv_job_execution" +participant Result as "dv_job_execution_result" +Scheduler->>API : 触发作业 +API->>JobExecution : 创建执行实例 +API->>API : 执行数据质量检查 +API->>Result : 写入检查结果 +Result-->>API : 返回结果 +JobExecution-->>API : 更新执行状态 +``` + +**图表来源** +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) +- [JobExecutionResult.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java) + +**章节来源** +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java#L1-L162) +- [JobExecutionResult.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java#L1-L95) + +### 元数据管理分析 +元数据管理模块负责存储和管理数据资产的信息,其核心是`dv_catalog_entity_instance`表。 + +#### 元数据管理实体关系图 +```mermaid +erDiagram +dv_catalog_entity_definition ||--o{ dv_catalog_entity_instance : "实例化" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_profile : "包含" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_rel : "关联" +dv_catalog_entity_instance ||--o{ dv_catalog_entity_tag_rel : "标记" +dv_catalog_tag_category ||--o{ dv_catalog_tag : "分类" +dv_catalog_tag ||--o{ dv_catalog_entity_tag_rel : "标记" +``` + +**图表来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L191-L353) + +**章节来源** +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java#L1-L79) + +### 配置管理分析 +配置管理模块通过`dv_config`表存储系统和工作空间级别的配置参数。 + +#### 配置管理流程图 +```mermaid +flowchart TD +Start([系统启动]) --> LoadConfig["从 dv_config 表加载配置"] +LoadConfig --> CheckDefault["检查是否为默认配置"] +CheckDefault --> |是| UseDefault["使用默认值"] +CheckDefault --> |否| UseCustom["使用自定义值"] +UseDefault --> End([配置生效]) +UseCustom --> End +``` + +**图表来源** +- [Config.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Config.java) + +**章节来源** +- [Config.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Config.java#L1-L67) + +## 依赖分析 +DataVines的数据库设计中存在多个关键依赖关系。`dv_job_execution`表依赖于`dv_job`表,通过`job_id`外键关联,确保每次执行都对应一个已定义的作业。`dv_job_execution_result`表依赖于`dv_job_execution`表,通过`job_execution_id`进行关联,形成执行-结果的层级结构。元数据管理模块中,`dv_catalog_entity_instance`表通过`datasource_id`依赖于`dv_datasource`表。Quartz调度框架的`QRTZ_TRIGGERS`表依赖于`QRTZ_JOB_DETAILS`表。这些依赖关系通过外键约束在数据库层面得到保证,确保了数据的完整性和一致性。 + +```mermaid +graph TD +dv_job --> dv_job_schedule +dv_job --> dv_job_execution +dv_job_execution --> dv_job_execution_result +dv_job_execution --> dv_command +dv_job --> dv_job_issue_rel +dv_job_schedule --> QRTZ_TRIGGERS +dv_job --> QRTZ_JOB_DETAILS +dv_datasource --> dv_catalog_entity_instance +dv_catalog_tag --> dv_catalog_entity_tag_rel +dv_catalog_entity_instance --> dv_catalog_entity_rel +``` + +**图表来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +**章节来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +## 性能考虑 +为了确保数据库的高性能,DataVines的数据库设计采用了多种优化策略。首先,对频繁查询的字段建立了索引,例如`dv_job_execution`表的`job_id`和`status`字段,`dv_job_execution_result`表的`job_execution_id`字段。其次,使用了复合主键和唯一键来保证数据的唯一性并加速查询,如`dv_catalog_entity_instance`表的`datasource_fqn_status_un`唯一键。对于大文本字段,如`parameter`和`properties`,使用了`text`或`longtext`类型,并建议在应用层进行合理的缓存。此外,`dv_job_execution`和`dv_job_execution_result`表可能会产生大量数据,建议根据`create_time`字段进行分表或归档,以避免单表数据量过大影响查询性能。 + +## 故障排除指南 +当遇到数据库相关问题时,可以参考以下指南进行排查。首先,检查`application.yaml`中的数据库连接配置是否正确,包括URL、用户名和密码。其次,查看`dv_job_execution`表中作业实例的状态(`status`字段),其值由`ExecutionStatus`枚举定义,如`0`表示已提交,`1`表示执行中,`6`表示失败。如果作业失败,可以检查`dv_job_execution`表中的`log_path`字段指向的日志文件。对于调度问题,检查`QRTZ_*`系列表中的记录,确认Quartz调度器是否正常工作。如果出现性能问题,可以使用`EXPLAIN`命令分析慢查询,并检查相关索引是否有效。 + +**章节来源** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java#L1-L158) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) + +## 结论 +DataVines的数据库设计是一个功能完整且结构清晰的数据治理体系。它有效地支持了数据质量监控和元数据管理两大核心功能。通过合理使用MyBatis-Plus和Quartz,实现了业务逻辑与持久化的良好分离。数据库模式设计考虑了数据完整性、查询性能和系统扩展性。未来,可以通过引入更细粒度的分区策略、优化历史数据归档机制以及加强监控告警功能,进一步提升系统的稳定性和可维护性。 + +## 附录 + +### 主要数据表结构说明 + +#### dv_job (数据质量作业表) +| 字段名 | 数据类型 | 约束 | 说明 | +| :--- | :--- | :--- | :--- | +| id | bigint(20) | PRIMARY KEY, AUTO_INCREMENT | 作业ID | +| name | varchar(255) | NOT NULL | 作业名称 | +| type | int(11) | NOT NULL | 作业类型 | +| datasource_id | bigint(20) | NOT NULL | 数据源ID | +| metric_type | varchar(255) | | 规则类型 | +| parameter | longtext | | 作业参数 | +| create_time | datetime | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 | +| update_time | datetime | NOT NULL, ON UPDATE CURRENT_TIMESTAMP | 更新时间 | + +#### dv_job_execution (作业执行实例表) +| 字段名 | 数据类型 | 约束 | 说明 | +| :--- | :--- | :--- | :--- | +| id | bigint(20) | PRIMARY KEY, AUTO_INCREMENT | 执行实例ID | +| job_id | bigint(20) | NOT NULL | 关联的作业ID | +| status | int(11) | | 执行状态 | +| start_time | datetime | | 开始时间 | +| end_time | datetime | | 结束时间 | +| create_time | datetime | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 | + +#### dv_job_execution_result (作业执行结果表) +| 字段名 | 数据类型 | 约束 | 说明 | +| :--- | :--- | :--- | :--- | +| id | bigint(20) | PRIMARY KEY, AUTO_INCREMENT | 结果ID | +| job_execution_id | bigint(20) | NOT NULL | 关联的执行实例ID | +| actual_value | decimal(20,4) | | 实际值 | +| expected_value | decimal(20,4) | | 期望值 | +| state | int(2) | NOT NULL | 结果状态 (0:成功, 1:失败) | +| create_time | datetime | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 | \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\346\225\260\346\215\256\347\224\237\345\221\275\345\221\250\346\234\237.md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\346\225\260\346\215\256\347\224\237\345\221\275\345\221\250\346\234\237.md" new file mode 100644 index 00000000..ae9aee16 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\346\225\260\346\215\256\347\224\237\345\221\275\345\221\250\346\234\237.md" @@ -0,0 +1,223 @@ +# 数据生命周期 + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [JobExecutionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionInfo.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) +- [ErrorDataStorageServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/ErrorDataStorageServiceImpl.java) +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java) + + +## 目录 +1. [引言](#引言) +2. [关键数据类型与生命周期](#关键数据类型与生命周期) +3. [数据保留策略设计](#数据保留策略设计) +4. [数据归档与清理机制](#数据归档与清理机制) +5. [数据版本管理与迁移](#数据版本管理与迁移) +6. [数据备份与恢复方案](#数据备份与恢复方案) +7. [结论](#结论) + +## 引言 + +DataVines 是一个开源的数据质量服务平台,旨在确保数据在集成和处理过程中的准确性。该平台支持多种数据质量检查规则,能够对数据进行完整性、一致性、有效性、时效性、唯一性和准确性等维度的评估。本文档旨在详细阐述 DataVines 中关键数据的生命周期管理策略,包括任务执行记录、执行结果等数据的创建、更新、归档和删除流程,以及数据保留策略的设计考虑、数据归档和清理的自动化脚本或配置、数据版本管理策略和数据备份与恢复方案。 + +## 关键数据类型与生命周期 + +### 任务执行记录 + +任务执行记录是 DataVines 中的核心数据之一,记录了每次任务执行的详细信息。这些记录包括任务的名称、类型、数据源、执行平台、执行引擎、错误数据存储类型、参数、状态、重试次数、超时时间、前置脚本、后置脚本、执行主机、应用ID、进程ID、执行文件路径、日志路径、提交时间、调度时间、开始时间、结束时间和创建时间等。 + +在 DataVines 中,任务执行记录的生命周期如下: +- **创建**:当用户创建一个新的任务时,系统会生成一个任务执行记录,并将其存储在数据库中。 +- **更新**:任务执行过程中,系统会不断更新任务执行记录的状态、开始时间、结束时间等信息。 +- **归档**:任务执行完成后,系统会将任务执行记录归档,以便后续查询和分析。 +- **删除**:根据数据保留策略,系统会在一定时间后删除过期的任务执行记录。 + +### 执行结果 + +执行结果是任务执行过程中产生的数据,包括实际值、期望值、比较符、阈值、质量评分等。这些结果用于评估数据质量,并生成数据质量报告。 + +在 DataVines 中,执行结果的生命周期如下: +- **创建**:任务执行过程中,系统会生成执行结果,并将其存储在数据库中。 +- **更新**:任务执行过程中,系统会不断更新执行结果的实际值、期望值、比较符、阈值、质量评分等信息。 +- **归档**:任务执行完成后,系统会将执行结果归档,以便后续查询和分析。 +- **删除**:根据数据保留策略,系统会在一定时间后删除过期的执行结果。 + +### 数据质量报告 + +数据质量报告是任务执行结果的汇总,用于展示数据质量的整体情况。报告包括数据源ID、实体级别、数据库名称、表名称、列名称、质量评分、报告日期等信息。 + +在 DataVines 中,数据质量报告的生命周期如下: +- **创建**:任务执行完成后,系统会生成数据质量报告,并将其存储在数据库中。 +- **更新**:系统会定期更新数据质量报告,以反映最新的数据质量情况。 +- **归档**:数据质量报告会定期归档,以便后续查询和分析。 +- **删除**:根据数据保留策略,系统会在一定时间后删除过期的数据质量报告。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L539-L580) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L586-L608) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L614-L626) + +## 数据保留策略设计 + +### 保留期限选择 + +DataVines 中的数据保留策略设计考虑了多个因素,包括业务需求、存储成本、合规要求等。具体保留期限的选择如下: +- **任务执行记录**:保留30天。这是因为大多数业务需求只需要最近30天的任务执行记录,超过30天的记录对业务影响较小,且占用大量存储空间。 +- **执行结果**:保留90天。执行结果是数据质量评估的重要依据,需要较长的保留时间以支持历史数据分析和问题追溯。 +- **数据质量报告**:保留180天。数据质量报告是数据质量的整体展示,需要更长的保留时间以支持长期趋势分析和合规审计。 + +### 设计考虑 + +- **业务需求**:保留期限的选择首先考虑业务需求,确保关键数据在需要时可用。 +- **存储成本**:过长的保留期限会增加存储成本,因此需要在业务需求和存储成本之间找到平衡。 +- **合规要求**:某些行业或地区有特定的合规要求,需要保留数据一定时间,以满足审计和监管要求。 + +**Section sources** +- [JobExecutionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionInfo.java#L26-L47) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java#L19-L28) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L439-L465) + +## 数据归档与清理机制 + +### 归档流程 + +DataVines 中的数据归档流程如下: +1. **识别过期数据**:系统定期扫描数据库,识别超过保留期限的数据。 +2. **归档数据**:将过期数据从主数据库中移出,存储到归档数据库中。 +3. **更新索引**:更新数据索引,确保归档数据可以被查询和分析。 + +### 清理流程 + +DataVines 中的数据清理流程如下: +1. **识别过期归档数据**:系统定期扫描归档数据库,识别超过归档保留期限的数据。 +2. **删除数据**:将过期的归档数据从归档数据库中删除。 +3. **更新日志**:记录数据删除操作,以便后续审计和问题追溯。 + +### 自动化脚本 + +DataVines 提供了自动化脚本,用于执行数据归档和清理操作。这些脚本可以通过定时任务调度,确保数据管理的自动化和高效性。 + +```bash +#!/bin/bash + +# 数据归档脚本 +archive_data() { + # 识别过期数据 + expired_data=$(mysql -u user -p password -e "SELECT id FROM dv_job_execution WHERE end_time < DATE_SUB(NOW(), INTERVAL 30 DAY);") + + # 归档数据 + for id in $expired_data; do + mysql -u user -p password -e "INSERT INTO dv_job_execution_archive SELECT * FROM dv_job_execution WHERE id = $id;" + mysql -u user -p password -e "DELETE FROM dv_job_execution WHERE id = $id;" + done +} + +# 数据清理脚本 +clean_data() { + # 识别过期归档数据 + expired_archive_data=$(mysql -u user -p password -e "SELECT id FROM dv_job_execution_archive WHERE end_time < DATE_SUB(NOW(), INTERVAL 180 DAY);") + + # 删除数据 + for id in $expired_archive_data; do + mysql -u user -p password -e "DELETE FROM dv_job_execution_archive WHERE id = $id;" + done +} + +# 调用脚本 +archive_data +clean_data +``` + +**Section sources** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L63-L89) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L439-L465) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L539-L580) + +## 数据版本管理与迁移 + +### 版本管理 + +DataVines 中的数据版本管理主要通过数据库模式变更来实现。每次数据库模式变更都会生成一个新的版本,记录变更前后的差异。这些版本信息存储在 `dv_catalog_schema_change` 表中,包括变更类型、数据库名称、表名称、列名称、变更前、变更后、更新用户ID和更新时间等。 + +### 迁移方法 + +DataVines 中的数据迁移方法如下: +1. **备份数据**:在进行数据库模式变更之前,先备份现有数据,以防止数据丢失。 +2. **执行变更**:执行数据库模式变更,包括添加、删除、修改表和列等操作。 +3. **验证数据**:变更完成后,验证数据的完整性和一致性,确保数据质量不受影响。 +4. **更新版本**:将变更信息记录到 `dv_catalog_schema_change` 表中,生成新的版本。 + +### 示例 + +假设需要在 `dv_job_execution` 表中添加一个 `log_path` 字段,迁移步骤如下: +1. **备份数据**: + ```sql + CREATE TABLE dv_job_execution_backup AS SELECT * FROM dv_job_execution; + ``` +2. **执行变更**: + ```sql + ALTER TABLE dv_job_execution ADD COLUMN log_path VARCHAR(255) DEFAULT NULL COMMENT 'log path'; + ``` +3. **验证数据**: + ```sql + SELECT * FROM dv_job_execution LIMIT 10; + ``` +4. **更新版本**: + ```sql + INSERT INTO dv_catalog_schema_change (parent_uuid, entity_uuid, change_type, database_name, table_name, column_name, change_before, change_after, update_by, update_time) + VALUES ('parent-uuid', 'entity-uuid', 'COLUMN_ADDED', 'dv', 'job_execution', 'log_path', NULL, 'VARCHAR(255)', 1, NOW()); + ``` + +**Section sources** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java#L1-L37) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java#L1-L73) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L171-L461) + +## 数据备份与恢复方案 + +### 备份方案 + +DataVines 中的数据备份方案如下: +1. **全量备份**:每天凌晨进行一次全量备份,将所有数据备份到远程存储中。 +2. **增量备份**:每小时进行一次增量备份,将自上次备份以来的新增数据备份到远程存储中。 +3. **备份验证**:定期验证备份数据的完整性和一致性,确保备份数据可以用于恢复。 + +### 恢复方案 + +DataVines 中的数据恢复方案如下: +1. **恢复全量备份**:当需要恢复数据时,首先恢复最近的一次全量备份。 +2. **恢复增量备份**:然后依次恢复自全量备份以来的所有增量备份,确保数据的完整性和一致性。 +3. **验证数据**:恢复完成后,验证数据的完整性和一致性,确保数据质量不受影响。 + +### 示例 + +假设需要恢复 `dv_job_execution` 表的数据,恢复步骤如下: +1. **恢复全量备份**: + ```sql + mysql -u user -p password dv < dv_job_execution_full_backup.sql + ``` +2. **恢复增量备份**: + ```sql + mysql -u user -p password dv < dv_job_execution_incremental_backup_1.sql + mysql -u user -p password dv < dv_job_execution_incremental_backup_2.sql + ``` +3. **验证数据**: + ```sql + SELECT * FROM dv_job_execution LIMIT 10; + ``` + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L166-L177) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L539-L580) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java#L19-L28) + +## 结论 + +DataVines 通过详细的数据生命周期管理策略,确保了数据的准确性、完整性和一致性。任务执行记录、执行结果和数据质量报告的创建、更新、归档和删除流程得到了有效管理,数据保留策略的设计考虑了业务需求、存储成本和合规要求。数据归档和清理机制通过自动化脚本实现了高效的数据管理,数据版本管理与迁移方法确保了数据库模式变更的安全性和可靠性,数据备份与恢复方案保障了数据安全性和业务连续性。这些策略共同构成了 DataVines 的数据管理框架,为用户提供了一个可靠的数据质量服务平台。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\347\264\242\345\274\225\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\347\264\242\345\274\225\347\255\226\347\225\245.md" new file mode 100644 index 00000000..8a0fc0c3 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\347\264\242\345\274\225\347\255\226\347\225\245.md" @@ -0,0 +1,200 @@ +# 索引策略 + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [JobExecutionMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobExecutionMapper.java) +- [JobExecutionResultMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobExecutionResultMapper.java) +- [DataSourceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java) +- [CatalogEntityInstanceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityInstanceMapper.java) +- [JobExecutionServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java) +- [SqlUtils.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/utils/SqlUtils.java) +- [HiveSqlUtils.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/utils/HiveSqlUtils.java) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + + +## 目录 +1. [引言](#引言) +2. [数据库索引概览](#数据库索引概览) +3. [核心表索引分析](#核心表索引分析) +4. [查询性能优化](#查询性能优化) +5. [索引维护最佳实践](#索引维护最佳实践) +6. [结论](#结论) + +## 引言 +DataVines 是一个数据质量监控平台,其核心功能包括数据源管理、规则作业调度、执行结果分析和质量报告生成。为了确保系统在处理大量数据时的高性能和响应速度,合理的数据库索引策略至关重要。本文档旨在全面分析 DataVines 项目中的数据库索引,解释每个关键索引的设计目的和优化目标,提供索引的创建语句和在 SQL 脚本中的位置,分析查询执行计划,展示索引如何影响查询性能,并为常见的查询模式推荐最佳索引策略。同时,文档化索引维护的最佳实践,包括何时创建新索引、何时删除无用索引。 + +## 数据库索引概览 +DataVines 项目使用 MySQL 作为其主要的数据库存储,其索引策略主要集中在以下几个方面: +- **主键索引**:每个表都有一个主键索引,用于唯一标识表中的每一行数据。 +- **唯一索引**:用于确保某些列的值在表中是唯一的,防止重复数据的插入。 +- **普通索引**:用于加速查询操作,特别是在 WHERE 子句中经常使用的列上。 + +通过分析 `scripts/sql/datavines-mysql.sql` 文件,我们可以看到所有表的创建语句和索引定义。这些索引的设计目的是为了优化数据的插入、更新、删除和查询操作,特别是在处理大量数据时,确保系统的高性能和响应速度。 + +## 核心表索引分析 + +### dv_job_execution 表 +`dv_job_execution` 表用于存储规则作业的运行实例信息。该表的索引设计如下: +- **主键索引**:`PRIMARY KEY (id)`,用于唯一标识每个作业运行实例。 +- **普通索引**:`KEY IDX_QRTZ_T_J (SCHED_NAME, JOB_NAME, JOB_GROUP)`,用于加速基于作业名称和组的查询。 + +```sql +CREATE TABLE `dv_job_execution` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL COMMENT '作业运行实例名称', + `job_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '作业ID', + `job_type` int(11) NOT NULL DEFAULT '0' COMMENT '作业类型', + `schema_name` varchar(128) DEFAULT NULL COMMENT '数据库名', + `table_name` varchar(128) DEFAULT NULL COMMENT '表名', + `column_name` varchar(128) DEFAULT NULL COMMENT '列名', + `metric_type` varchar(255) DEFAULT NULL COMMENT '规则类型', + `datasource_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '数据源ID', + `execute_platform_type` varchar(128) DEFAULT NULL COMMENT '运行平台类型', + `execute_platform_parameter` text COMMENT '运行平台参数', + `engine_type` varchar(128) DEFAULT NULL COMMENT '运行引擎类型', + `engine_parameter` text COMMENT '运行引擎参数', + `error_data_storage_type` varchar(128) DEFAULT NULL COMMENT '错误数据存储类型', + `error_data_storage_parameter` text COMMENT '错误数据存储参数', + `error_data_file_name` varchar(255) DEFAULT NULL COMMENT '错误数据存储文件名', + `parameter` longtext NOT NULL COMMENT '作业运行参数', + `status` int(11) DEFAULT NULL COMMENT '作业运行状态', + `retry_times` int(11) DEFAULT NULL COMMENT '重试次数', + `retry_interval` int(11) DEFAULT NULL COMMENT '重试间隔', + `timeout` int(11) DEFAULT NULL COMMENT '超时时间', + `timeout_strategy` int(11) DEFAULT NULL COMMENT '超时处理策略', + `pre_sql` text DEFAULT NULL COMMENT '前置脚本', + `post_sql` text DEFAULT NULL COMMENT '后置脚本', + `tenant_code` varchar(255) DEFAULT NULL COMMENT '代理用户', + `execute_host` varchar(255) DEFAULT NULL COMMENT '执行任务的主机', + `application_id` varchar(255) DEFAULT NULL COMMENT 'yarn application id', + `application_tag` varchar(255) DEFAULT NULL COMMENT 'yarn application tags', + `process_id` int(11) DEFAULT NULL COMMENT 'process id', + `execute_file_path` varchar(255) DEFAULT NULL COMMENT 'execute file path', + `log_path` varchar(255) DEFAULT NULL COMMENT 'log path', + `env` text COMMENT '运行环境的配置信息', + `submit_time` datetime DEFAULT NULL COMMENT '提交时间', + `schedule_time` datetime DEFAULT NULL COMMENT '调度时间', + `start_time` datetime DEFAULT NULL COMMENT '开始时间', + `end_time` datetime DEFAULT NULL COMMENT '结束时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='规则作业运行实例'; +``` + +**设计目的和优化目标**: +- **主键索引**:确保每个作业运行实例的唯一性,加速基于 `id` 的查询操作。 +- **普通索引**:加速基于 `job_id`、`datasource_id`、`status` 等字段的查询操作,特别是在分页查询和统计分析中。 + +### dv_job_execution_result 表 +`dv_job_execution_result` 表用于存储规则作业的运行结果。该表的索引设计如下: +- **主键索引**:`PRIMARY KEY (id)`,用于唯一标识每个运行结果。 +- **唯一索引**:`UNIQUE KEY execution_id_un (job_execution_id, metric_unique_key)`,确保每个作业运行实例的每个规则的唯一性。 + +```sql +CREATE TABLE `dv_job_execution_result` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `job_execution_id` bigint(20) DEFAULT NULL COMMENT '任务执行实例ID', + `metric_unique_key` varchar(255) DEFAULT NULL COMMENT '规则运行唯一标识', + `metric_type` varchar(255) DEFAULT NULL COMMENT '规则类型', + `metric_dimension` varchar(255) DEFAULT NULL COMMENT '规则维度', + `metric_name` varchar(255) DEFAULT NULL COMMENT '规则名称', + `database_name` varchar(128) DEFAULT NULL COMMENT '数据库名称', + `table_name` varchar(128) DEFAULT NULL COMMENT '表名称', + `column_name` varchar(128) DEFAULT NULL COMMENT '列名称', + `actual_value` decimal(20,4) DEFAULT NULL COMMENT '实际值', + `expected_value` decimal(20,4) DEFAULT NULL COMMENT '期望值', + `expected_type` varchar(255) DEFAULT NULL COMMENT '期望值类型', + `result_formula` varchar(255) DEFAULT NULL COMMENT '计算结果公式', + `operator` varchar(255) DEFAULT NULL COMMENT '比较符', + `threshold` decimal(20,4) DEFAULT NULL COMMENT '阈值', + `score` decimal(20,4) DEFAULT 0 COMMENT '质量评分', + `state` int(2) NOT NULL DEFAULT '0' COMMENT '结果 1:success/2:fail', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `execution_id_un` (`job_execution_id`,`metric_unique_key`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='规则作业运行结果'; +``` + +**设计目的和优化目标**: +- **主键索引**:确保每个运行结果的唯一性,加速基于 `id` 的查询操作。 +- **唯一索引**:确保每个作业运行实例的每个规则的唯一性,防止重复数据的插入,加速基于 `job_execution_id` 和 `metric_unique_key` 的查询操作。 + +### dv_datasource 表 +`dv_datasource` 表用于存储数据源信息。该表的索引设计如下: +- **主键索引**:`PRIMARY KEY (id)`,用于唯一标识每个数据源。 +- **唯一索引**:`UNIQUE KEY datasource_un (name)`,确保数据源名称的唯一性。 + +```sql +CREATE TABLE `dv_datasource` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `uuid` varchar(64) NOT NULL COMMENT '数据源UUID', + `name` varchar(255) NOT NULL COMMENT '数据源名称', + `type` varchar(255) NOT NULL COMMENT '数据源类型', + `param` text NOT NULL COMMENT '数据源参数', + `param_code` text NULL COMMENT '数据源参数MD5值', + `workspace_id` bigint(20) NOT NULL COMMENT '工作空间ID', + `create_by` bigint(20) NOT NULL COMMENT '创建用户ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) NOT NULL COMMENT '更新用户ID', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `datasource_un` (`name`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据源'; +``` + +**设计目的和优化目标**: +- **主键索引**:确保每个数据源的唯一性,加速基于 `id` 的查询操作。 +- **唯一索引**:确保数据源名称的唯一性,防止重复数据的插入,加速基于 `name` 的查询操作。 + +## 查询性能优化 + +### 查询执行计划分析 +通过分析 `JobExecutionMapper.java` 和 `JobExecutionResultMapper.java` 中的查询方法,我们可以看到 DataVines 如何利用索引来优化查询性能。例如,`getJobExecutionPage` 方法使用了分页查询,通过 `job_id`、`datasource_id`、`status` 等字段进行过滤,这些字段上的索引可以显著提高查询性能。 + +```java +IPage getJobExecutionPage(Page page, + @Param("searchVal") String searchVal, + @Param("jobId") Long jobId, + @Param("datasourceId") Long datasourceId, + @Param("status") Integer status, + @Param("metricType") String metricType, @Param("schemaName") String schemaName, + @Param("tableName") String tableName, @Param("columnName") String columnName, + @Param("startTime") String startTime, @Param("endTime") String endTime, + @Param("schemaSearch") String schemaSearch, + @Param("tableSearch") String tableSearch, + @Param("columnSearch") String columnSearch); +``` + +### 索引使用建议 +- **创建复合索引**:对于经常一起使用的查询条件,建议创建复合索引。例如,`dv_job_execution` 表中的 `job_id` 和 `status` 字段可以创建一个复合索引,以加速基于这两个字段的查询。 +- **避免过度索引**:过多的索引会增加数据插入和更新的开销,因此应根据实际查询需求合理创建索引。 +- **定期分析和优化**:定期使用 `ANALYZE TABLE` 命令分析表的统计信息,确保查询优化器能够选择最优的执行计划。 + +## 索引维护最佳实践 + +### 创建新索引 +- **评估查询需求**:在创建新索引之前,应评估查询需求,确保索引能够显著提高查询性能。 +- **选择合适的字段**:选择经常用于 WHERE 子句、JOIN 条件和 ORDER BY 子句的字段创建索引。 +- **考虑索引类型**:根据数据类型和查询需求选择合适的索引类型,如 B-Tree 索引、哈希索引等。 + +### 删除无用索引 +- **监控索引使用情况**:定期监控索引的使用情况,识别长时间未使用的索引。 +- **评估删除影响**:在删除索引之前,应评估删除索引对现有查询性能的影响。 +- **逐步删除**:建议逐步删除无用索引,避免一次性删除多个索引导致系统性能下降。 + +## 结论 +DataVines 项目通过合理的数据库索引策略,确保了系统在处理大量数据时的高性能和响应速度。通过对核心表的索引分析,我们可以看到每个索引的设计目的和优化目标。通过查询执行计划的分析,我们可以了解索引如何影响查询性能。最后,通过索引维护的最佳实践,我们可以确保索引的持续优化,提高系统的整体性能。 + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [JobExecutionMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobExecutionMapper.java) +- [JobExecutionResultMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobExecutionResultMapper.java) +- [DataSourceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java) +- [CatalogEntityInstanceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityInstanceMapper.java) +- [JobExecutionServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java) +- [SqlUtils.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/utils/SqlUtils.java) +- [HiveSqlUtils.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/utils/HiveSqlUtils.java) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\344\273\273\345\212\241\346\211\247\350\241\214\350\241\250 (job_execution).md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\344\273\273\345\212\241\346\211\247\350\241\214\350\241\250 (job_execution).md" new file mode 100644 index 00000000..32e7b925 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\344\273\273\345\212\241\346\211\247\350\241\214\350\241\250 (job_execution).md" @@ -0,0 +1,267 @@ +# 任务执行表 (job_execution) + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) + + +## 目录 +1. [表结构概览](#表结构概览) +2. [字段详细说明](#字段详细说明) +3. [状态字段说明](#状态字段说明) +4. [执行平台字段说明](#执行平台字段说明) +5. [设计考虑](#设计考虑) +6. [关联关系](#关联关系) +7. [核心作用](#核心作用) + +## 表结构概览 + +`dv_job_execution` 表用于存储数据质量规则作业的运行实例信息。该表记录了每次作业执行的详细信息,包括执行状态、时间戳、配置参数等,是任务调度和监控系统的核心组成部分。 + +```mermaid +erDiagram +dv_job_execution { +bigint id PK +varchar name +bigint job_id FK +int job_type +varchar schema_name +varchar table_name +varchar column_name +varchar metric_type +bigint datasource_id +varchar execute_platform_type +text execute_platform_parameter +varchar engine_type +text engine_parameter +varchar error_data_storage_type +text error_data_storage_parameter +varchar error_data_file_name +longtext parameter +int status +int retry_times +int retry_interval +int timeout +int timeout_strategy +text pre_sql +text post_sql +varchar tenant_code +varchar execute_host +varchar application_id +varchar application_tag +int process_id +varchar execute_file_path +varchar log_path +text env +datetime submit_time +datetime schedule_time +datetime start_time +datetime end_time +datetime create_time +datetime update_time +} +dv_job ||--o{ dv_job_execution : "1:N" +``` + +**图表来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L537-L580) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) + +## 字段详细说明 + +`dv_job_execution` 表包含以下字段: + +| 字段名 | 数据类型 | 允许空值 | 默认值 | 说明 | +| :--- | :--- | :--- | :--- | :--- | +| `id` | bigint(20) | 否 | 自增 | 主键,作业运行实例ID | +| `name` | varchar(255) | 否 | - | 作业运行实例名称 | +| `job_id` | bigint(20) | 否 | '-1' | 外键,关联到dv_job表的ID,表示该执行实例对应的作业定义 | +| `job_type` | int(11) | 否 | '0' | 作业类型 | +| `schema_name` | varchar(128) | 是 | NULL | 数据库名 | +| `table_name` | varchar(128) | 是 | NULL | 表名 | +| `column_name` | varchar(128) | 是 | NULL | 列名 | +| `metric_type` | varchar(255) | 是 | NULL | 规则类型 | +| `datasource_id` | bigint(20) | 否 | '-1' | 数据源ID | +| `execute_platform_type` | varchar(128) | 是 | NULL | 运行平台类型(如:YARN, LOCAL, LIVY) | +| `execute_platform_parameter` | text | 是 | NULL | 运行平台参数 | +| `engine_type` | varchar(128) | 是 | NULL | 运行引擎类型(如:SPARK, FLINK) | +| `engine_parameter` | text | 是 | NULL | 运行引擎参数 | +| `error_data_storage_type` | varchar(128) | 是 | NULL | 错误数据存储类型 | +| `error_data_storage_parameter` | text | 是 | NULL | 错误数据存储参数 | +| `error_data_file_name` | varchar(255) | 是 | NULL | 错误数据存储文件名 | +| `parameter` | longtext | 否 | - | 作业运行参数,包含具体的规则配置 | +| `status` | int(11) | 是 | NULL | 作业运行状态,对应ExecutionStatus枚举 | +| `retry_times` | int(11) | 是 | NULL | 重试次数 | +| `retry_interval` | int(11) | 是 | NULL | 重试间隔(秒) | +| `timeout` | int(11) | 是 | NULL | 超时时间(秒) | +| `timeout_strategy` | int(11) | 是 | NULL | 超时处理策略,对应TimeoutStrategy枚举 | +| `pre_sql` | text | 是 | NULL | 前置脚本 | +| `post_sql` | text | 是 | NULL | 后置脚本 | +| `tenant_code` | varchar(255) | 是 | NULL | 代理用户 | +| `execute_host` | varchar(255) | 是 | NULL | 执行任务的主机 | +| `application_id` | varchar(255) | 是 | NULL | YARN application ID | +| `application_tag` | varchar(255) | 是 | NULL | YARN application tags | +| `process_id` | int(11) | 是 | NULL | 进程ID | +| `execute_file_path` | varchar(255) | 是 | NULL | 执行文件路径 | +| `log_path` | varchar(255) | 是 | NULL | 日志路径 | +| `env` | text | 是 | NULL | 运行环境的配置信息 | +| `submit_time` | datetime | 是 | NULL | 提交时间 | +| `schedule_time` | datetime | 是 | NULL | 调度时间 | +| `start_time` | datetime | 是 | NULL | 开始时间 | +| `end_time` | datetime | 是 | NULL | 结束时间 | +| `create_time` | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | +| `update_time` | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | + +**字段来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L537-L580) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) + +## 状态字段说明 + +`status` 字段表示作业的执行状态,其值对应 `ExecutionStatus` 枚举类。以下是各状态码的含义: + +| 状态码 | 状态描述 | 中文描述 | 业务含义 | +| :--- | :--- | :--- | :--- | +| 0 | submitted | 已提交 | 作业已成功提交到调度系统,等待执行 | +| 1 | running | 执行中 | 作业正在执行中 | +| 2 | ready pause | 准备暂停 | 作业准备进入暂停状态 | +| 3 | pause | 暂停 | 作业已暂停 | +| 4 | ready stop | 准备停止 | 作业准备停止 | +| 5 | stop | 停止 | 作业已停止 | +| 6 | failure | 失败 | 作业执行失败 | +| 7 | success | 成功 | 作业执行成功 | +| 8 | need fault tolerance | 需要容错 | 作业需要进行容错处理 | +| 9 | kill | 强制终止 | 作业被强制终止 | +| 10 | waiting thread | 等待线程 | 作业正在等待可用线程 | +| 11 | waiting_summit | 待提交 | 作业等待被提交 | + +这些状态用于监控作业的生命周期,从提交、执行、完成到最终状态的全过程。 + +**状态字段来源** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) + +## 执行平台字段说明 + +`execute_platform_type` 字段表示作业的执行引擎平台,常见的值包括: + +- **YARN**: 在YARN集群上执行,适用于大规模分布式计算 +- **LOCAL**: 在本地执行,适用于小规模数据或测试场景 +- **LIVY**: 通过Livy服务提交Spark作业,提供RESTful接口 + +`engine_type` 字段表示具体的执行引擎,常见的值包括: + +- **SPARK**: 使用Apache Spark作为执行引擎 +- **FLINK**: 使用Apache Flink作为执行引擎 + +这些字段的设计使得系统能够灵活支持多种执行平台和引擎,满足不同场景下的性能和资源需求。 + +**执行平台字段来源** +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) + +## 设计考虑 + +`dv_job_execution` 表的设计考虑了以下几个关键方面: + +1. **详细的执行时间戳**:表中包含了 `submit_time`、`schedule_time`、`start_time` 和 `end_time` 四个时间戳字段,用于精确记录作业的生命周期。这些时间戳对于性能分析、调度延迟监控和故障排查至关重要。 + +2. **外部ID关联**:通过 `application_id` 字段存储执行引擎(如YARN)分配的应用程序ID,可以方便地与外部系统进行关联和查询,实现跨系统的监控和管理。 + +3. **灵活的参数存储**:使用 `text` 和 `longtext` 类型的字段(如 `parameter`、`engine_parameter`)来存储JSON格式的配置参数,提供了极大的灵活性,可以适应各种复杂的配置需求而无需频繁修改表结构。 + +4. **枚举类型优化**:将状态和策略等固定值定义为枚举类型(`ExecutionStatus`、`TimeoutStrategy`),并在数据库中存储为整数,既保证了数据的一致性,又提高了查询性能。 + +5. **审计和追踪**:`create_time` 和 `update_time` 字段提供了完整的审计追踪能力,记录了每条记录的创建和修改时间。 + +**设计考虑来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L537-L580) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) + +## 关联关系 + +`dv_job_execution` 表与 `dv_job` 表存在明确的关联关系: + +- **外键关系**:`dv_job_execution.job_id` 字段是外键,引用 `dv_job.id` 字段,形成一对多的关系。一个作业定义(`dv_job`)可以有多个执行实例(`dv_job_execution`)。 +- **数据继承**:执行实例继承了作业定义中的大部分配置信息,如数据源、规则类型、执行引擎等,同时可以覆盖某些参数以实现灵活的运行时配置。 +- **历史追踪**:通过这种关联,系统可以追踪每个作业的历史执行记录,分析其执行趋势和性能变化。 + +```mermaid +erDiagram +dv_job { +bigint id PK +varchar name +int type +bigint datasource_id +varchar metric_type +varchar execute_platform_type +varchar engine_type +text parameter +int retry_times +int timeout +int timeout_strategy +text pre_sql +text post_sql +bigint create_by +datetime create_time +bigint update_by +datetime update_time +} +dv_job_execution { +bigint id PK +varchar name +bigint job_id FK +int job_type +varchar schema_name +varchar table_name +varchar column_name +varchar metric_type +bigint datasource_id +varchar execute_platform_type +varchar engine_parameter +text parameter +int status +int retry_times +int retry_interval +int timeout +int timeout_strategy +text pre_sql +text post_sql +varchar tenant_code +varchar execute_host +varchar application_id +datetime submit_time +datetime schedule_time +datetime start_time +datetime end_time +datetime create_time +datetime update_time +} +dv_job ||--o{ dv_job_execution : "1:N" +``` + +**关联关系来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L498-L534) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) + +## 核心作用 + +`dv_job_execution` 表在数据质量平台中扮演着核心角色,主要作用包括: + +1. **任务调度**:作为调度系统的核心数据表,记录了所有待执行、正在执行和已完成的作业实例,是调度器决策的基础。 + +2. **执行监控**:通过实时更新 `status`、`start_time`、`end_time` 等字段,提供作业执行的实时状态监控,支持告警和通知功能。 + +3. **性能分析**:利用详细的执行时间戳,可以分析作业的调度延迟、执行时长等性能指标,帮助优化系统配置。 + +4. **故障排查**:当作业失败时,可以通过该表的记录(包括错误日志路径、执行主机等)快速定位问题原因。 + +5. **历史审计**:保存所有作业的执行历史,支持按时间、状态、作业类型等维度进行查询和统计,满足审计和合规要求。 + +6. **结果关联**:作为 `dv_job_execution_result` 表的父表,通过 `id` 字段关联具体的执行结果,形成完整的数据质量评估链条。 + +**核心作用来源** +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) +- [JobExecutionMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobExecutionMapper.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\344\273\273\345\212\241\350\241\250 (job).md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\344\273\273\345\212\241\350\241\250 (job).md" new file mode 100644 index 00000000..810839de --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\344\273\273\345\212\241\350\241\250 (job).md" @@ -0,0 +1,360 @@ +# 任务表 (job) + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L498-L534) +- [Job.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java) +- [JobType.java](file://datavines-common/src/main/java/io/datavines/common/enums/JobType.java) +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) +- [dv_job_schedule](file://scripts/sql/datavines-mysql.sql#L658-L675) +- [dv_job_execution](file://scripts/sql/datavines-mysql.sql#L537-L580) +- [dv_datasource](file://scripts/sql/datavines-mysql.sql#L415-L432) +- [dv_user](file://scripts/sql/datavines-mysql.sql#L789-L800) + + +## 目录 +1. [任务表结构](#任务表结构) +2. [字段详细说明](#字段详细说明) +3. [业务含义解释](#业务含义解释) +4. [表设计考虑](#表设计考虑) +5. [与其他表的关系](#与其他表的关系) + +## 任务表结构 + +任务表(job)是数据质量管理系统中的核心表之一,用于存储数据质量检查任务的配置信息。该表定义了数据质量检查的各种参数和配置。 + +```mermaid +erDiagram +dv_job { +bigint id PK +varchar name +int type +bigint datasource_id FK +bigint datasource_id_2 +varchar schema_name +varchar table_name +varchar column_name +text selected_column +varchar metric_type +varchar execute_platform_type +text execute_platform_parameter +varchar engine_type +text engine_parameter +bigint error_data_storage_id FK +tinyint is_error_data_output_to_datasource +varchar error_data_output_to_datasource_database +longtext parameter +int retry_times +int retry_interval +int timeout +int timeout_strategy +text pre_sql +text post_sql +bigint tenant_code +bigint env +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +``` + +**图表来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L498-L534) + +**章节来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L498-L534) + +## 字段详细说明 + +任务表包含以下字段,每个字段都有特定的数据类型和约束: + +| 字段名 | 数据类型 | 是否可为空 | 默认值 | 说明 | +|--------|---------|-----------|--------|------| +| id | bigint(20) | 否 | 无 | 主键,自增 | +| name | varchar(255) | 是 | NULL | 作业名称 | +| type | int(11) | 否 | 0 | 作业类型 | +| datasource_id | bigint(20) | 否 | 无 | 数据源ID | +| datasource_id_2 | bigint(20) | 是 | NULL | 数据源2ID | +| schema_name | varchar(128) | 是 | NULL | 数据库名 | +| table_name | varchar(128) | 是 | NULL | 表名 | +| column_name | varchar(128) | 是 | NULL | 列名 | +| selected_column | text | 是 | NULL | DataProfile选中的列 | +| metric_type | varchar(255) | 是 | NULL | 规则类型 | +| execute_platform_type | varchar(128) | 是 | NULL | 运行平台类型 | +| execute_platform_parameter | text | 是 | NULL | 运行平台参数 | +| engine_type | varchar(128) | 是 | NULL | 运行引擎类型 | +| engine_parameter | text | 是 | NULL | 运行引擎参数 | +| error_data_storage_id | bigint(20) | 是 | NULL | 错误数据存储ID | +| is_error_data_output_to_datasource | tinyint(1) | 是 | 0 | 错误数据是否输出至数据源 | +| error_data_output_to_datasource_database | varchar(255) | 是 | NULL | 错误数据存储数据库 | +| parameter | longtext | 是 | NULL | 作业参数 | +| retry_times | int(11) | 是 | NULL | 重试次数 | +| retry_interval | int(11) | 是 | NULL | 重试间隔 | +| timeout | int(11) | 是 | NULL | 任务超时时间 | +| timeout_strategy | int(11) | 是 | NULL | 超时策略 | +| pre_sql | text | 是 | NULL | 前置脚本 | +| post_sql | text | 是 | NULL | 后置脚本 | +| tenant_code | bigint(20) | 是 | NULL | 代理用户 | +| env | bigint(20) | 是 | NULL | 环境配置 | +| create_by | bigint(20) | 否 | 无 | 创建用户ID | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | + +**章节来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L498-L534) + +## 业务含义解释 + +### 核心字段业务含义 + +**id**: 任务的唯一标识符,作为主键使用,确保每个任务都有唯一的标识。 + +**name**: 任务的名称,用于标识和区分不同的数据质量检查任务。任务名称与数据源ID、数据库名、表名和列名组合形成唯一约束,确保在同一数据源和表上的相同检查任务不会重复创建。 + +**type**: 任务类型,使用`JobType`枚举类型表示。根据`JobType.java`文件中的定义,任务类型可能包括数据质量检查、元数据抓取等不同类型。 + +**datasource_id**: 数据源ID,关联到`dv_datasource`表,标识该任务所检查的数据源。这是实现多租户隔离的关键字段之一。 + +**metric_type**: 规则类型,表示任务的具体检查类型。根据业务需求,可能包括: +- 单表检查:对单个表的数据质量进行检查 +- 跨表检查:对多个表之间的数据一致性进行检查 +- 数据新鲜度检查:检查数据的更新时间是否符合预期 +- 数据完整性检查:检查数据是否存在缺失或异常 + +**parameter**: 作业参数,以JSON格式存储任务的详细配置。这个字段包含了任务执行所需的所有配置信息,如检查规则的具体参数、阈值设置等。 + +**status**: 任务状态,虽然在表结构中没有直接名为status的字段,但任务的生命周期管理通过相关联的`dv_job_execution`表中的状态字段实现。任务可能的状态包括:待执行、执行中、成功、失败、已停止等。 + +### 配置相关字段 + +**execute_platform_type** 和 **execute_platform_parameter**: 运行平台类型和参数,指定任务在哪个平台执行(如YARN、Kubernetes等)以及相应的平台配置。 + +**engine_type** 和 **engine_parameter**: 运行引擎类型和参数,指定使用哪个计算引擎(如Spark、Flink等)以及引擎的配置参数。 + +**pre_sql** 和 **post_sql**: 前置脚本和后置脚本,分别在任务执行前和执行后运行的SQL脚本,用于数据准备和清理工作。 + +**retry_times** 和 **retry_interval**: 重试次数和重试间隔,定义了任务失败后的重试策略。 + +**timeout** 和 **timeout_strategy**: 超时时间和超时策略,用于防止任务无限期运行。超时策略可能包括终止任务、告警等。 + +**章节来源** +- [Job.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java) +- [JobType.java](file://datavines-common/src/main/java/io/datavines/common/enums/JobType.java) +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) + +## 表设计考虑 + +### 状态管理与生命周期 + +任务表通过与`dv_job_execution`表的关联来管理任务的生命周期。`dv_job_execution`表记录了每次任务执行的实例,包括执行状态、开始时间、结束时间等信息。这种设计将任务定义与任务执行分离,使得: + +1. 可以保存任务的历史执行记录 +2. 支持任务的重复执行和调度 +3. 便于分析任务执行的趋势和性能 + +任务的状态管理主要通过`dv_job_execution`表中的`status`字段实现,而不是在`dv_job`表中直接存储状态。这种设计考虑了任务可能有多个执行实例,每个实例都有自己的状态。 + +### 多租户隔离设计 + +任务表通过`workspace_id`字段实现多租户隔离。虽然在`dv_job`表中没有直接的`workspace_id`字段,但通过`datasource_id`关联到`dv_datasource`表,而`dv_datasource`表包含`workspace_id`字段,从而实现了间接的多租户隔离。 + +这种设计的优势包括: +- 数据源级别的隔离:不同工作空间的用户只能访问自己工作空间内的数据源 +- 任务级别的隔离:用户只能创建和管理自己工作空间内数据源相关的任务 +- 权限控制:基于工作空间的权限体系,可以精细控制用户对任务的访问权限 + +### 性能与扩展性考虑 + +任务表的设计考虑了性能和扩展性: +- 使用bigint作为主键类型,支持大规模数据量 +- 对经常查询的字段(如name, datasource_id, schema_name等)建立了复合唯一索引 +- 将大文本字段(如parameter, execute_platform_parameter等)设置为可为空,避免不必要的存储开销 +- 使用标准化的数据类型,便于跨数据库平台迁移 + +**章节来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L498-L534) +- [dv_datasource](file://scripts/sql/datavines-mysql.sql#L415-L432) +- [dv_job_execution](file://scripts/sql/datavines-mysql.sql#L537-L580) + +## 与其他表的关系 + +任务表与其他核心表存在以下关系: + +```mermaid +erDiagram +dv_job ||--o{ dv_job_schedule : "1:N" +dv_job ||--o{ dv_job_execution : "1:N" +dv_job }o--|| dv_datasource : "N:1" +dv_job }o--|| dv_user : "N:1" +dv_job }o--|| dv_error_data_storage : "N:1" +dv_job { +bigint id PK +varchar name +int type +bigint datasource_id FK +bigint datasource_id_2 +varchar schema_name +varchar table_name +varchar column_name +text selected_column +varchar metric_type +varchar execute_platform_type +text execute_platform_parameter +varchar engine_type +text engine_parameter +bigint error_data_storage_id FK +tinyint is_error_data_output_to_datasource +varchar error_data_output_to_datasource_database +longtext parameter +int retry_times +int retry_interval +int timeout +int timeout_strategy +text pre_sql +text post_sql +bigint tenant_code +bigint env +bigint create_by FK +bigint create_time +bigint update_by FK +bigint update_time +} +dv_job_schedule { +bigint id PK +varchar type +text param +bigint job_id FK +varchar cron_expression +tinyint status +datetime start_time +datetime end_time +bigint create_by +datetime create_time +bigint update_by +datetime update_time +} +dv_job_execution { +bigint id PK +varchar name +bigint job_id FK +int job_type +varchar schema_name +varchar table_name +varchar column_name +varchar metric_type +bigint datasource_id +varchar execute_platform_type +text execute_platform_parameter +varchar engine_type +text engine_parameter +varchar error_data_storage_type +text error_data_storage_parameter +varchar error_data_file_name +longtext parameter +int status +int retry_times +int retry_interval +int timeout +int timeout_strategy +text pre_sql +text post_sql +varchar tenant_code +varchar execute_host +varchar application_id +varchar application_tag +int process_id +varchar execute_file_path +varchar log_path +text env +datetime submit_time +datetime schedule_time +datetime start_time +datetime end_time +datetime create_time +datetime update_time +} +dv_datasource { +bigint id PK +varchar uuid +varchar name +varchar type +text param +text param_code +bigint workspace_id +bigint create_by +datetime create_time +bigint update_by +datetime update_time +} +dv_user { +bigint id PK +varchar username +varchar password +varchar email +varchar phone +tinyint admin +datetime create_time +datetime update_time +} +dv_error_data_storage { +bigint id PK +varchar name +varchar type +text param +bigint workspace_id +bigint create_by +datetime create_time +bigint update_by +datetime update_time +} +``` + +**图表来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L498-L534) +- [dv_job_schedule](file://scripts/sql/datavines-mysql.sql#L658-L675) +- [dv_job_execution](file://scripts/sql/datavines-mysql.sql#L537-L580) +- [dv_datasource](file://scripts/sql/datavines-mysql.sql#L415-L432) +- [dv_user](file://scripts/sql/datavines-mysql.sql#L789-L800) +- [dv_error_data_storage](file://scripts/sql/datavines-mysql.sql#L465-L481) + +### 与`dv_job_schedule`表的关系 + +`dv_job`表与`dv_job_schedule`表是一对多的关系。一个任务可以有多个调度配置,但每个调度配置只属于一个任务。`dv_job_schedule`表中的`job_id`字段外键引用`dv_job`表的`id`字段。 + +这种设计支持: +- 任务的多种调度方式(如定时调度、事件触发调度等) +- 调度配置的灵活管理 +- 调度历史的记录和分析 + +### 与`dv_job_execution`表的关系 + +`dv_job`表与`dv_job_execution`表是一对多的关系。一个任务定义可以产生多个执行实例,每个执行实例记录了任务在特定时间点的执行情况。`dv_job_execution`表中的`job_id`字段外键引用`dv_job`表的`id`字段。 + +这种设计实现了: +- 任务执行历史的完整记录 +- 执行结果的追溯和分析 +- 性能监控和优化 + +### 与`dv_datasource`表的关系 + +`dv_job`表与`dv_datasource`表是多对一的关系。多个任务可以关联到同一个数据源,但每个任务只能关联到一个主数据源。`dv_job`表中的`datasource_id`字段外键引用`dv_datasource`表的`id`字段。 + +这种设计确保了: +- 任务与数据源的明确关联 +- 数据源配置的集中管理 +- 多租户环境下的数据隔离 + +### 与`dv_user`表的关系 + +`dv_job`表与`dv_user`表是多对一的关系。多个任务可以由同一个用户创建,但每个任务只能由一个用户创建和更新。`dv_job`表中的`create_by`和`update_by`字段外键引用`dv_user`表的`id`字段。 + +这种设计支持: +- 用户权限管理 +- 操作审计 +- 责任追溯 + +**章节来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [Job.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\345\267\245\344\275\234\347\251\272\351\227\264\350\241\250 (workspace).md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\345\267\245\344\275\234\347\251\272\351\227\264\350\241\250 (workspace).md" new file mode 100644 index 00000000..969ec3b5 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\345\267\245\344\275\234\347\251\272\351\227\264\350\241\250 (workspace).md" @@ -0,0 +1,278 @@ +# 工作空间表 (workspace) + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L822-L834) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [UserWorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/UserWorkSpace.java) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java) +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java) + + +## 目录 +1. [工作空间表结构](#工作空间表结构) +2. [字段详细说明](#字段详细说明) +3. [表设计考虑](#表设计考虑) +4. [关联关系](#关联关系) +5. [核心作用](#核心作用) + +## 工作空间表结构 + +工作空间表(dv_workspace)是DataVines系统中的核心元数据表,用于组织和管理用户的工作环境。该表定义了工作空间的基本信息,作为多租户数据隔离和权限控制的基础单元。 + +```sql +CREATE TABLE `dv_workspace` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL COMMENT '工作空间名称', + `create_by` bigint(20) NOT NULL COMMENT '创建用户ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) NOT NULL COMMENT '更新用户ID', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `workspace_un` (`name`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工作空间'; +``` + +**表来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L822-L834) + +## 字段详细说明 + +工作空间表包含以下字段,每个字段都有特定的业务含义和数据类型: + +**id** +- **数据类型**: bigint(20) +- **约束**: 主键,自增 +- **业务含义**: 工作空间的唯一标识符,系统自动生成的主键,用于唯一标识每个工作空间实例。 + +**name** +- **数据类型**: varchar(255) +- **约束**: NOT NULL,唯一索引 (workspace_un) +- **业务含义**: 工作空间的名称,用于标识和区分不同的工作空间。名称必须唯一,不能重复。 + +**create_by** +- **数据类型**: bigint(20) +- **约束**: NOT NULL +- **业务含义**: 创建该工作空间的用户ID,记录了工作空间的创建者,用于审计和权限追溯。 + +**create_time** +- **数据类型**: datetime +- **约束**: NOT NULL,默认值为CURRENT_TIMESTAMP +- **业务含义**: 工作空间的创建时间,系统自动记录工作空间创建的时间戳。 + +**update_by** +- **数据类型**: bigint(20) +- **约束**: NOT NULL +- **业务含义**: 最后更新该工作空间的用户ID,记录了最近一次修改工作空间信息的用户。 + +**update_time** +- **数据类型**: datetime +- **约束**: NOT NULL,默认值为CURRENT_TIMESTAMP,更新时自动更新为CURRENT_TIMESTAMP +- **业务含义**: 工作空间的最后更新时间,系统自动记录工作空间信息最后一次被修改的时间戳。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L822-L834) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) + +## 表设计考虑 + +工作空间表的设计考虑了多租户数据隔离、权限控制和系统可扩展性等关键因素: + +1. **多租户数据隔离**:通过工作空间作为数据隔离的基本单元,不同工作空间之间的数据和配置相互隔离,确保了多租户环境下的数据安全和隐私保护。 + +2. **权限控制基础**:工作空间是权限控制的基本单元,用户必须先加入某个工作空间才能访问该空间内的资源。通过`dv_user_workspace`关联表实现用户与工作空间的多对多关系,支持灵活的权限管理。 + +3. **命名唯一性**:工作空间名称设置了唯一索引,确保系统中不存在同名的工作空间,避免了命名冲突。 + +4. **审计追踪**:通过`create_by`、`update_by`、`create_time`和`update_time`字段,完整记录了工作空间的生命周期信息,便于审计和问题追溯。 + +5. **扩展性**:表结构设计简洁,只包含核心字段,其他扩展属性可以通过关联表或配置表进行管理,保证了核心表的稳定性和性能。 + +**Section sources** +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java) + +## 关联关系 + +工作空间表与其他核心表存在多种关联关系,构成了系统的权限和资源管理框架: + +```mermaid +erDiagram +dv_workspace { +bigint id PK +varchar name UK +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_user { +bigint id PK +varchar username UK +varchar password +varchar email +tinyint admin +datetime create_time +datetime update_time +} +dv_user_workspace { +bigint id PK +bigint user_id FK +bigint workspace_id FK +bigint role_id FK +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_datasource { +bigint id PK +varchar uuid UK +varchar name +varchar type +text param +bigint workspace_id FK +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_job { +bigint id PK +varchar name +int type +bigint datasource_id FK +bigint datasource_id_2 +varchar schema_name +varchar table_name +varchar column_name +text selected_column +varchar metric_type +varchar execute_platform_type +text execute_platform_parameter +varchar engine_type +text engine_parameter +bigint error_data_storage_id +tinyint is_error_data_output_to_datasource +varchar error_data_output_to_datasource_database +longtext parameter +int retry_times +int retry_interval +int timeout +int timeout_strategy +text pre_sql +text post_sql +bigint tenant_code +bigint env +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_env { +bigint id PK +varchar name UK +text env +bigint workspace_id FK +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_error_data_storage { +bigint id PK +varchar name +varchar type +text param +bigint workspace_id FK +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_sla { +bigint id PK +bigint workspace_id FK +varchar name +varchar description +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_tenant { +bigint id PK +varchar tenant UK +bigint workspace_id FK +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_config { +bigint id PK +bigint workspace_id FK +varchar var_key +text var_value +tinyint is_default +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_catalog_tag_category { +bigint id PK +varchar uuid UK +varchar name +bigint workspace_id FK +bigint create_by FK +datetime create_time +bigint update_by FK +datetime update_time +} +dv_workspace ||--o{ dv_user_workspace : "包含" +dv_user ||--o{ dv_user_workspace : "属于" +dv_workspace ||--o{ dv_datasource : "管理" +dv_workspace ||--o{ dv_env : "配置" +dv_workspace ||--o{ dv_error_data_storage : "存储" +dv_workspace ||--o{ dv_sla : "关联" +dv_workspace ||--o{ dv_tenant : "使用" +dv_workspace ||--o{ dv_config : "拥有" +dv_workspace ||--o{ dv_catalog_tag_category : "分类" +dv_workspace ||--o{ dv_job : "运行" +``` + +**Diagram sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L822-L834) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L806-L819) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L417-L432) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L437-L449) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L468-L481) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L707-L718) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L774-L786) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L837-L851) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L340-L352) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L500-L534) + +## 核心作用 + +工作空间表在DataVines系统中扮演着核心角色,主要体现在以下几个方面: + +1. **资源组织单元**:工作空间是系统中资源组织的基本单元,所有数据源、作业、环境配置等资源都归属于特定的工作空间,实现了资源的逻辑分组和管理。 + +2. **团队协作基础**:通过工作空间,团队成员可以共享数据源、作业配置和质量规则,支持团队协作开发和维护数据质量任务。 + +3. **权限控制边界**:工作空间定义了权限控制的边界,用户必须先加入工作空间才能访问其中的资源,实现了基于工作空间的访问控制。 + +4. **多租户支持**:通过工作空间实现了多租户架构,不同组织或团队可以拥有独立的工作空间,确保数据和配置的隔离。 + +5. **配置管理**:工作空间关联了环境配置、租户配置和系统参数等,是配置管理的核心,支持不同工作空间有不同的运行环境和参数设置。 + +6. **审计和追踪**:通过记录创建者和更新者信息,工作空间支持完整的操作审计,便于追踪变更历史和责任归属。 + +7. **扩展性**:工作空间的设计支持系统的水平扩展,可以轻松添加新的工作空间来支持更多的团队或项目。 + +**Section sources** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java) +- [WorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/WorkSpaceService.java) +- [UserWorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/UserWorkSpace.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\346\225\260\346\215\256\346\272\220\350\241\250 (data_source).md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\346\225\260\346\215\256\346\272\220\350\241\250 (data_source).md" new file mode 100644 index 00000000..8856ccfc --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\346\225\260\346\215\256\346\272\220\350\241\250 (data_source).md" @@ -0,0 +1,71 @@ +# 数据源表 (data_source) + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L417-L432) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java#L1-L70) +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java#L1-L40) +- [MysqlDataSourceInfo.java](file://datavines-connector/ datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDataSourceInfo.java#L1-L50) + + +## 目录 +1. [字段列表](#字段列表) +2. [业务含义说明](#业务含义说明) +3. [表设计考虑](#表设计考虑) +4. [索引与约束](#索引与约束) +5. [系统角色](#系统角色) + +## 字段列表 + +数据源表(`dv_datasource`)包含以下字段: + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 说明 | +| :--- | :--- | :--- | :--- | :--- | +| `id` | bigint(20) | 否 | 无 | 主键,自增ID | +| `uuid` | varchar(64) | 否 | 无 | 数据源UUID,唯一标识 | +| `name` | varchar(255) | 否 | 无 | 数据源名称 | +| `type` | varchar(255) | 否 | 无 | 数据源类型,如mysql、postgresql等 | +| `param` | text | 否 | 无 | 数据源参数,以JSON格式存储连接信息 | +| `param_code` | text | 是 | NULL | 数据源参数的MD5值,用于快速比较参数是否变更 | +| `workspace_id` | bigint(20) | 否 | 无 | 所属工作空间ID | +| `create_by` | bigint(20) | 否 | 无 | 创建用户ID | +| `create_time` | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | +| `update_by` | bigint(20) | 否 | 无 | 更新用户ID | +| `update_time` | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | + +**字段来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L417-L432) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java#L1-L70) + +## 业务含义说明 + +- **`name` 字段**:表示数据源的名称,是用户在系统中识别该数据源的主要标识。名称在工作空间内必须唯一。 +- **`type` 字段**:表示数据源的类型,决定了系统使用哪个连接器(Connector)来访问该数据源。根据代码中的 `MysqlDataSourceInfo.java` 文件,支持的类型包括 `mysql`、`postgresql`、`oracle` 等。 +- **`param` 字段**:以JSON格式存储连接该数据源所需的所有参数。这些参数通常包括主机地址(host)、端口(port)、用户名(username)、密码(password)等。密码等敏感信息在此JSON中存储时会被加密。 +- **`param_code` 字段**:存储`param`字段内容的MD5哈希值。当用户修改数据源配置时,系统可以通过比较新的参数MD5值与数据库中存储的`param_code`来判断连接参数是否真正发生了变化,从而避免不必要的元数据刷新等操作。 +- **`workspace_id` 字段**:表示该数据源属于哪个工作空间,用于实现多租户和资源隔离。 + +**字段来源** +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java#L1-L40) +- [MysqlDataSourceInfo.java](file://datavines-connector/ datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDataSourceInfo.java#L1-L50) + +## 表设计考虑 + +- **使用JSON格式存储连接参数**:`param`字段使用TEXT类型存储JSON字符串,这种设计提供了极大的灵活性。不同的数据库类型(如MySQL, MongoDB, Hive)具有完全不同的连接参数,使用JSON可以轻松容纳这些差异,而无需为每种数据库类型设计固定的列。这使得系统可以方便地扩展对新数据源类型的支持。 +- **使用加密字段存储敏感信息**:虽然`param`字段本身是明文存储的JSON,但根据系统设计惯例和安全要求,其中的密码(password)等敏感信息在存入数据库前会被加密。系统在使用时会先解密再建立连接,从而保护了用户的敏感凭证。 +- **UUID作为唯一标识**:除了自增的`id`,还使用了`uuid`字段作为数据源的全局唯一标识。这有利于在分布式系统或数据同步场景下进行数据识别和关联。 + +## 索引与约束 + +- **主键约束 (Primary Key)**:`id` 字段是表的主键,确保了每条记录的唯一性。 +- **唯一索引 (Unique Key)**:`datasource_un` 索引作用于 `name` 字段,确保在同一个工作空间内,数据源名称不能重复,防止用户创建同名的数据源造成混淆。 + +**索引来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L431-L432) + +## 系统角色 + +`dv_datasource` 表在系统中扮演着**所有数据质量检查任务的数据来源配置中心**的角色。它是整个数据质量平台的基础。其他核心功能都依赖于此表: +- **数据质量检查任务 (Job)**:在创建数据质量检查任务时,必须从 `dv_datasource` 表中选择一个已配置的数据源作为检查目标。 +- **元数据抓取**:系统通过读取此表中的连接信息,定期连接到各个数据源,抓取数据库、表、列等元数据信息,并存储在 `dv_catalog_entity_instance` 等表中。 +- **连接测试**:前端UI提供的“测试连接”功能,其后端逻辑就是根据此表中存储的 `param` 信息,尝试建立数据库连接,并返回结果。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\347\224\250\346\210\267\350\241\250 (user).md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\347\224\250\346\210\267\350\241\250 (user).md" new file mode 100644 index 00000000..f5f5154d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\347\224\250\346\210\267\350\241\250 (user).md" @@ -0,0 +1,213 @@ +# 用户表 (user) + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) +- [dv_access_token](file://scripts/sql/datavines-mysql.sql) +- [dv_workspace](file://scripts/sql/datavines-mysql.sql) +- [dv_user_workspace](file://scripts/sql/datavines-mysql.sql) + + +## 目录 +1. [用户表结构](#用户表结构) +2. [字段详细说明](#字段详细说明) +3. [表设计考虑](#表设计考虑) +4. [与其他表的关系](#与其他表的关系) +5. [在用户认证和权限管理中的作用](#在用户认证和权限管理中的作用) + +## 用户表结构 + +用户表 `dv_user` 是系统中用于存储用户基本信息的核心表,其结构定义如下: + +```sql +CREATE TABLE `dv_user` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `username` varchar(255) NOT NULL COMMENT '用户名', + `password` varchar(255) NOT NULL COMMENT '密码', + `email` varchar(255) NOT NULL COMMENT '邮箱', + `phone` varchar(127) DEFAULT NULL COMMENT '手机号码', + `admin` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否为管理员', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `user_un` (`username`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户'; +``` + +**表名**: `dv_user` +**存储引擎**: InnoDB +**字符集**: utf8mb4 +**注释**: 用户 + +**表结构来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L788-L803) + +## 字段详细说明 + +用户表包含以下字段,每个字段都有特定的数据类型和业务含义: + +### id +- **数据类型**: `bigint(20)` +- **约束**: `NOT NULL AUTO_INCREMENT`, `PRIMARY KEY` +- **说明**: 用户的唯一标识符,作为主键使用,自增。 + +### username +- **数据类型**: `varchar(255)` +- **约束**: `NOT NULL`, `UNIQUE KEY user_un` +- **说明**: 用户名,用于用户登录和系统内唯一标识用户。在系统中必须唯一,通过唯一约束保证。 + +### password +- **数据类型**: `varchar(255)` +- **约束**: `NOT NULL` +- **说明**: 存储加密后的密码。系统使用 BCrypt 算法对用户密码进行哈希处理,确保即使数据库泄露,原始密码也无法被轻易还原。密码长度要求在6-20个字符之间。 + +### email +- **数据类型**: `varchar(255)` +- **约束**: `NOT NULL` +- **说明**: 用户的邮箱地址,用于账户验证、密码重置和系统通知。系统通过正则表达式 `^[a-z_0-9.-]{1,64}@([a-z0-9-]{1,200}.){1,5}[a-z]{1,6}$` 验证邮箱格式的有效性。 + +### phone +- **数据类型**: `varchar(127)` +- **约束**: `DEFAULT NULL` +- **说明**: 用户的手机号码,可选字段,用于多因素认证或紧急联系。 + +### admin +- **数据类型**: `tinyint(1)` +- **约束**: `NOT NULL DEFAULT '0'` +- **说明**: 标识用户是否为管理员。`0` 表示普通用户,`1` 表示管理员。管理员拥有系统最高权限,可以管理其他用户和系统配置。 + +### create_time +- **数据类型**: `datetime` +- **约束**: `NOT NULL DEFAULT CURRENT_TIMESTAMP` +- **说明**: 用户账户的创建时间,由数据库自动填充当前时间戳。 + +### update_time +- **数据类型**: `datetime` +- **约束**: `NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP` +- **说明**: 用户信息最后更新时间,每次用户信息被修改时,数据库会自动更新此字段为当前时间戳。 + +**字段说明来源** +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java#L30-L61) +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java#L52-L160) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java#L171) + +## 表设计考虑 + +用户表的设计充分考虑了安全性、唯一性和数据完整性: + +1. **唯一性约束**: 通过 `UNIQUE KEY user_un (username)` 确保用户名的唯一性,防止重复注册。这是用户登录和身份识别的基础。 + +2. **密码安全**: 密码字段使用 BCrypt 哈希算法进行加密存储。BCrypt 是一种自适应的哈希函数,包含盐值(salt)机制,能有效抵御彩虹表攻击。在 `UserServiceImpl.java` 中,注册和修改密码时都调用了 `BCrypt.hashpw()` 方法进行加密。 + +3. **数据完整性**: 所有关键字段如 `username`、`password`、`email` 都设置为 `NOT NULL`,确保用户信息的完整性。`admin` 字段有默认值 `0`,确保新用户默认为普通用户。 + +4. **时间戳管理**: `create_time` 和 `update_time` 字段由数据库自动管理,减少了应用层的复杂性,并确保了时间记录的准确性。 + +5. **索引优化**: 主键 `id` 自动创建索引,`username` 字段的唯一索引也提供了快速的查找性能,这对于用户登录验证等高频操作至关重要。 + +**设计考虑来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L788-L803) +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java#L87-L88) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L25-L84) + +## 与其他表的关系 + +用户表 `dv_user` 与其他多个表存在关联关系,构成了系统的权限和数据管理基础: + +### 与 `dv_access_token` 表的关系 +- **关系类型**: 一对多 +- **外键**: `dv_access_token.user_id` 引用 `dv_user.id` +- **说明**: 每个用户可以拥有多个访问令牌(access token),用于API调用的身份验证。当用户登录成功后,系统会生成一个token并存储在此表中,关联到对应的用户。 + +### 与 `dv_workspace` 表的关系 +- **关系类型**: 多对多 +- **中间表**: `dv_user_workspace` +- **说明**: 用户和工作空间是多对多关系。一个用户可以属于多个工作空间,一个工作空间也可以有多个用户。这种关系通过中间表 `dv_user_workspace` 实现,该表包含 `user_id` 和 `workspace_id` 两个外键。 + +### 与 `dv_user_workspace` 表的关系 +- **关系类型**: 一对多 +- **外键**: `dv_user_workspace.user_id` 引用 `dv_user.id` +- **说明**: 该表记录了用户与工作空间的关联关系,同时还包含 `role_id` 字段,用于定义用户在特定工作空间中的角色和权限。 + +```mermaid +erDiagram +dv_user { +bigint id PK +varchar username UK +varchar password +varchar email +varchar phone +tinyint admin +datetime create_time +datetime update_time +} +dv_access_token { +bigint id PK +bigint workspace_id FK +bigint user_id FK +varchar token +datetime expire_time +bigint create_by +datetime create_time +bigint update_by +datetime update_time +} +dv_workspace { +bigint id PK +varchar name UK +bigint create_by +datetime create_time +bigint update_by +datetime update_time +} +dv_user_workspace { +bigint id PK +bigint user_id FK +bigint workspace_id FK +bigint role_id +bigint create_by +datetime create_time +bigint update_by +datetime update_time +} +dv_user ||--o{ dv_access_token : "1:N" +dv_user ||--o{ dv_user_workspace : "1:N" +dv_workspace ||--o{ dv_user_workspace : "1:N" +``` + +**关系图来源** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L451-L463) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L806-L819) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L822-L834) + +## 在用户认证和权限管理中的作用 + +用户表 `dv_user` 是整个系统用户认证和权限管理的基石,其作用体现在以下几个方面: + +1. **用户认证 (Authentication)**: + - **登录验证**: 当用户尝试登录时,系统通过 `getByUsername` 方法根据用户名查询用户信息,然后使用 `BCrypt.checkpw()` 方法验证提供的密码与数据库中存储的哈希密码是否匹配。 + - **密码策略**: 系统强制要求密码长度在6-20个字符之间,通过 `CommonConstants.REG_USER_PASSWORD` 正则表达式进行验证,增强了账户安全性。 + +2. **权限管理 (Authorization)**: + - **管理员权限**: `admin` 字段是区分普通用户和管理员的关键。管理员可以执行系统级操作,如用户管理、系统配置等。 + - **工作空间权限**: 通过 `dv_user_workspace` 表,系统实现了基于工作空间的权限隔离。用户的权限不仅取决于其自身属性,还取决于其在特定工作空间中的角色(`role_id`)。 + +3. **用户生命周期管理**: + - **注册**: 新用户注册时,系统会检查用户名是否已存在,若不存在则创建新用户记录,并为其创建一个默认工作空间。 + - **密码重置**: 用户可以修改密码,系统会使用新的盐值重新哈希密码,确保旧密码的哈希值失效。 + - **信息更新**: 用户可以更新个人信息,`update_time` 字段会自动记录最后修改时间。 + +4. **审计与追踪**: + - 所有与用户相关的操作(创建、更新)都有时间戳记录,便于审计和问题排查。 + - `create_by` 和 `update_by` 字段在相关表中记录了操作者的ID,实现了操作溯源。 + +综上所述,`dv_user` 表不仅是存储用户基本信息的地方,更是整个系统安全架构的核心组件,支撑着从用户登录到权限控制的完整流程。 + +**权限管理来源** +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java#L58-L77) +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java#L80-L118) +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java#L133-L149) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216.md" "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216.md" new file mode 100644 index 00000000..e89929b2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216/\350\241\250\347\273\223\346\236\204\350\257\264\346\230\216.md" @@ -0,0 +1,424 @@ +# 表结构说明 + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java) +- [Job.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) +- [JobExecutionResult.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java) +- [AccessToken.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/AccessToken.java) +- [JobSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java) +- [Sla.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Sla.java) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java) +- [Command.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Command.java) +- [Issue.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Issue.java) +- [ErrorDataStorage.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/ErrorDataStorage.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) + + +## 目录 +1. [简介](#简介) +2. [核心表结构](#核心表结构) + 1. [用户表 (dv_user)](#用户表-dv_user) + 2. [工作空间表 (dv_workspace)](#工作空间表-dv_workspace) + 3. [数据源表 (dv_datasource)](#数据源表-dv_datasource) + 4. [作业表 (dv_job)](#作业表-dv_job) + 5. [作业执行实例表 (dv_job_execution)](#作业执行实例表-dv_job_execution) + 6. [作业执行结果表 (dv_job_execution_result)](#作业执行结果表-dv_job_execution_result) + 7. [访问令牌表 (dv_access_token)](#访问令牌表-dv_access_token) + 8. [作业调度表 (dv_job_schedule)](#作业调度表-dv_job_schedule) + 9. [SLA表 (dv_sla)](#sla表-dv_sla) + 10. [实体实例表 (dv_catalog_entity_instance)](#实体实例表-dv_catalog_entity_instance) + 11. [命令表 (dv_command)](#命令表-dv_command) + 12. [告警信息表 (dv_issue)](#告警信息表-dv_issue) + 13. [错误数据存储表 (dv_error_data_storage)](#错误数据存储表-dv_error_data_storage) + 14. [租户表 (dv_tenant)](#租户表-dv_tenant) + +## 简介 +DataVines是一个数据质量管理系统,其数据库设计围绕数据源管理、作业调度、执行监控和质量报告等核心功能。本文档详细说明了系统中关键表的结构,包括字段定义、数据类型、约束和业务含义。通过分析SQL脚本和Java实体类,确保文档与实际代码库保持一致。 + +## 核心表结构 + +### 用户表 (dv_user) +用户表存储系统用户的基本信息,是权限管理和身份验证的基础。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识用户记录 | +| username | varchar(255) | 否 | 无 | 用户名 | 用户登录系统的唯一标识 | +| password | varchar(255) | 否 | 无 | 密码 | 经过加密的用户密码 | +| email | varchar(255) | 否 | 无 | 邮箱 | 用户的联系邮箱,用于通知和找回密码 | +| phone | varchar(127) | 是 | NULL | 手机号码 | 用户的联系电话 | +| admin | tinyint(1) | 否 | 0 | 是否为管理员 | 标识用户是否具有管理员权限,0为普通用户,1为管理员 | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`username`字段设置为非空且无默认值,确保每个用户都有唯一的登录名。`password`字段存储加密后的密码,保障系统安全。`admin`字段使用`tinyint(1)`类型,以最小的存储空间表示布尔状态。 + +**表注释**:`COMMENT='用户'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L788-L800) +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java#L1-L62) + +### 工作空间表 (dv_workspace) +工作空间表用于组织和隔离不同团队或项目的资源,实现多租户管理。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识工作空间记录 | +| name | varchar(255) | 否 | 无 | 工作空间名称 | 工作空间的显示名称 | +| create_by | bigint(20) | 否 | 无 | 创建用户ID | 创建该工作空间的用户ID | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | 最后更新该工作空间的用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`name`字段为非空,确保工作空间有明确的标识。`create_by`和`update_by`字段关联`dv_user`表的`id`,实现操作审计。 + +**表注释**:`COMMENT='工作空间'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L801-L815) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java#L1-L56) + +### 数据源表 (dv_datasource) +数据源表存储连接到外部数据系统的配置信息,是数据质量检查的起点。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识数据源记录 | +| uuid | varchar(64) | 否 | 无 | 数据源UUID | 全局唯一标识符 | +| name | varchar(255) | 否 | 无 | 数据源名称 | 数据源的显示名称 | +| type | varchar(255) | 否 | 无 | 数据源类型 | 如MySQL, PostgreSQL, Hive等 | +| param | text | 否 | 无 | 数据源参数 | JSON格式的连接参数,如主机、端口、数据库名、用户名、密码等 | +| param_code | text | 是 | NULL | 数据源参数MD5值 | `param`字段的MD5哈希值,用于快速比较配置是否变更 | +| workspace_id | bigint(20) | 否 | 无 | 工作空间ID | 所属工作空间的ID | +| create_by | bigint(20) | 否 | 无 | 创建用户ID | 创建该数据源的用户ID | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | 最后更新该数据源的用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`param`字段使用`text`类型存储JSON,提供了极大的灵活性来适应不同数据源的连接需求。`param_code`字段存储MD5值,避免了在比较时解析整个JSON字符串,提高了性能。`name`字段有唯一索引,防止在同一工作空间内创建同名数据源。 + +**表注释**:`COMMENT='数据源'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L414-L433) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java#L1-L70) + +### 作业表 (dv_job) +作业表定义了数据质量检查的规则和配置,是系统的核心配置表。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识作业记录 | +| name | varchar(255) | 是 | NULL | 作业名称 | 作业的显示名称 | +| type | int(11) | 否 | 0 | 作业类型 | 枚举值,标识作业的类别 | +| datasource_id | bigint(20) | 否 | 无 | 数据源ID | 关联的数据源ID | +| datasource_id_2 | bigint(20) | 是 | NULL | 数据源2ID | 用于对比的第二个数据源ID | +| schema_name | varchar(128) | 是 | NULL | 数据库名 | 目标数据库名称 | +| table_name | varchar(128) | 是 | NULL | 表名 | 目标表名称 | +| column_name | varchar(128) | 是 | NULL | 列名 | 目标列名称 | +| selected_column | text | 是 | NULL | DataProfile 选中的列 | JSON格式,存储DataProfile作业中选中的列 | +| metric_type | varchar(255) | 是 | NULL | 规则类型 | 指定执行的质量检查规则,如"列非空率"、"列唯一值个数"等 | +| execute_platform_type | varchar(128) | 是 | NULL | 运行平台类型 | 如YARN, LOCAL等 | +| execute_platform_parameter | text | 是 | NULL | 运行平台参数 | JSON格式,平台特定的配置 | +| engine_type | varchar(128) | 是 | NULL | 运行引擎类型 | 如Spark, Flink等 | +| engine_parameter | text | 是 | NULL | 运行引擎参数 | JSON格式,引擎特定的配置 | +| error_data_storage_id | bigint(20) | 是 | NULL | 错误数据存储ID | 存储错误数据的目标ID | +| is_error_data_output_to_datasource | tinyint(1) | 是 | 0 | 错误数据是否输出至数据源 | 布尔值,控制错误数据的输出位置 | +| error_data_output_to_datasource_database | varchar(255) | 是 | NULL | 错误数据存储数据库 | 错误数据输出到数据源时的数据库名 | +| parameter | longtext | 是 | NULL | 作业参数 | JSON格式,存储作业的详细配置 | +| retry_times | int(11) | 是 | NULL | 重试次数 | 作业失败后的重试次数 | +| retry_interval | int(11) | 是 | NULL | 重试间隔 | 重试之间的等待时间(秒) | +| timeout | int(11) | 是 | NULL | 任务超时时间 | 作业执行的超时时间(秒) | +| timeout_strategy | int(11) | 是 | NULL | 超时策略 | 超时后的处理策略,如警告或失败 | +| pre_sql | text | 是 | NULL | 前置脚本 | 作业执行前运行的SQL脚本 | +| post_sql | text | 是 | NULL | 后置脚本 | 作业执行后运行的SQL脚本 | +| tenant_code | bigint(20) | 是 | NULL | 代理用户 | 执行作业时使用的租户/用户 | +| env | bigint(20) | 是 | NULL | 环境配置 | 关联的环境配置ID | +| create_by | bigint(20) | 否 | 无 | 创建用户ID | 创建该作业的用户ID | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | 最后更新该作业的用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`parameter`字段使用`longtext`类型,可以存储复杂的JSON配置。`name`、`datasource_id`、`schema_name`、`table_name`和`column_name`组合成唯一索引,确保在同一数据源、数据库、表和列上不能创建同名的作业。`type`字段使用`int`类型,与Java中的`JobType`枚举对应。 + +**表注释**:`COMMENT='规则作业'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L497-L535) +- [Job.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java#L1-L126) + +### 作业执行实例表 (dv_job_execution) +作业执行实例表记录了每次作业运行的具体实例,是执行历史和监控的基础。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识作业执行实例记录 | +| name | varchar(255) | 否 | 无 | 作业运行实例名称 | 本次运行的名称 | +| job_id | bigint(20) | 否 | -1 | 作业ID | 关联的作业ID | +| job_type | int(11) | 否 | 0 | 作业类型 | 从作业继承的类型 | +| schema_name | varchar(128) | 是 | NULL | 数据库名 | 从作业继承的数据库名 | +| table_name | varchar(128) | 是 | NULL | 表名 | 从作业继承的表名 | +| column_name | varchar(128) | 是 | NULL | 列名 | 从作业继承的列名 | +| metric_type | varchar(255) | 是 | NULL | 规则类型 | 从作业继承的规则类型 | +| datasource_id | bigint(20) | 否 | -1 | 数据源ID | 从作业继承的数据源ID | +| execute_platform_type | varchar(128) | 是 | NULL | 运行平台类型 | 从作业继承的运行平台类型 | +| execute_platform_parameter | text | 是 | NULL | 运行平台参数 | 从作业继承的运行平台参数 | +| engine_type | varchar(128) | 是 | NULL | 运行引擎类型 | 从作业继承的运行引擎类型 | +| engine_parameter | text | 是 | NULL | 运行引擎参数 | 从作业继承的运行引擎参数 | +| error_data_storage_type | varchar(128) | 是 | NULL | 错误数据存储类型 | 从作业继承的错误数据存储类型 | +| error_data_storage_parameter | text | 是 | NULL | 错误数据存储参数 | 从作业继承的错误数据存储参数 | +| error_data_file_name | varchar(255) | 是 | NULL | 错误数据存储文件名 | 生成的错误数据文件名 | +| parameter | longtext | 否 | 无 | 作业运行参数 | 本次运行的实际参数,可能与作业定义不同 | +| status | int(11) | 是 | NULL | 作业运行状态 | 枚举值,如等待、运行中、成功、失败等 | +| retry_times | int(11) | 是 | NULL | 重试次数 | 本次运行的重试次数 | +| retry_interval | int(11) | 是 | NULL | 重试间隔 | 本次运行的重试间隔 | +| timeout | int(11) | 是 | NULL | 超时时间 | 本次运行的超时时间 | +| timeout_strategy | int(11) | 是 | NULL | 超时处理策略 | 本次运行的超时处理策略 | +| pre_sql | text | 是 | NULL | 前置脚本 | 本次运行的前置脚本 | +| post_sql | text | 是 | NULL | 后置脚本 | 本次运行的后置脚本 | +| tenant_code | varchar(255) | 是 | NULL | 代理用户 | 本次运行使用的代理用户 | +| execute_host | varchar(255) | 是 | NULL | 执行任务的主机 | 执行该作业的服务器主机名 | +| application_id | varchar(255) | 是 | NULL | yarn application id | YARN应用ID | +| application_tag | varchar(255) | 是 | NULL | yarn application tags | YARN应用标签 | +| process_id | int(11) | 是 | NULL | process id | 本地进程ID | +| execute_file_path | varchar(255) | 是 | NULL | execute file path | 执行文件的路径 | +| log_path | varchar(255) | 是 | NULL | log path | 日志文件的路径 | +| env | text | 是 | NULL | 运行环境的配置信息 | JSON格式,本次运行的环境配置 | +| submit_time | datetime | 是 | NULL | 提交时间 | 作业被提交到队列的时间 | +| schedule_time | datetime | 是 | NULL | 调度时间 | 作业计划执行的时间 | +| start_time | datetime | 是 | NULL | 开始时间 | 作业实际开始执行的时间 | +| end_time | datetime | 是 | NULL | 结束时间 | 作业执行结束的时间 | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:该表存储了作业运行时的完整上下文,包括从`dv_job`继承的配置和运行时动态生成的信息(如`execute_host`、`application_id`)。`status`字段用于跟踪作业的生命周期。`submit_time`、`schedule_time`、`start_time`和`end_time`字段提供了完整的执行时间线。 + +**表注释**:`COMMENT='规则作业运行实例'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L536-L581) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java#L1-L162) + +### 作业执行结果表 (dv_job_execution_result) +作业执行结果表存储了每次质量检查的具体结果,是生成报告和告警的依据。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识结果记录 | +| job_execution_id | bigint(20) | 是 | NULL | 任务执行实例ID | 关联的作业执行实例ID | +| metric_unique_key | varchar(255) | 是 | NULL | 规则运行唯一标识 | 本次规则运行的唯一键 | +| metric_name | varchar(255) | 是 | NULL | 规则名称 | 规则的显示名称 | +| metric_dimension | varchar(255) | 是 | NULL | 规则维度 | 规则的分类,如"完整性"、"准确性"等 | +| metric_type | varchar(255) | 是 | NULL | 规则类型 | 规则的技术类型 | +| database_name | varchar(128) | 是 | NULL | 数据库名称 | 检查的数据库名 | +| table_name | varchar(128) | 是 | NULL | 表名称 | 检查的表名 | +| column_name | varchar(128) | 是 | NULL | 列名称 | 检查的列名 | +| actual_value | decimal(20,4) | 是 | NULL | 实际值 | 规则检查得到的实际结果 | +| expected_value | decimal(20,4) | 是 | NULL | 期望值 | 规则定义的期望结果 | +| expected_type | varchar(255) | 是 | NULL | 期望值类型 | 期望值的类型,如"固定值"、"历史平均值"等 | +| result_formula | varchar(255) | 是 | NULL | 计算结果公式 | 用于计算最终结果的公式 | +| operator | varchar(255) | 是 | NULL | 比较符 | 用于比较实际值和期望值的操作符,如">", "<", "=" | +| threshold | decimal(20,4) | 是 | NULL | 阈值 | 比较的阈值 | +| score | decimal(20,4) | 是 | 0 | 质量评分 | 本次检查的质量得分 | +| state | int(2) | 否 | 0 | 结果 | 检查结果状态,1为成功,2为失败 | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`actual_value`和`expected_value`使用`decimal(20,4)`类型,保证了数值计算的精度。`state`字段使用`int`类型,与Java中的状态枚举对应。`job_execution_id`和`metric_unique_key`组合成唯一索引,确保同一执行实例中不会重复记录同一规则的结果。 + +**表注释**:`COMMENT='规则作业运行结果'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L582-L609) +- [JobExecutionResult.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java#L1-L95) + +### 访问令牌表 (dv_access_token) +访问令牌表用于管理API访问的令牌,实现安全的远程调用。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识令牌记录 | +| workspace_id | bigint(20) | 否 | 无 | 工作空间ID | 令牌所属的工作空间ID | +| user_id | bigint(20) | 否 | 无 | 用户ID | 令牌所属的用户ID | +| token | varchar(1024) | 否 | 无 | token | 实际的令牌字符串 | +| expire_time | datetime | 否 | 无 | 过期时间 | 令牌的过期时间 | +| create_by | bigint(20) | 否 | 无 | 创建用户ID | 创建该令牌的用户ID | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | 最后更新该令牌的用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`token`字段长度为1024,足够存储长令牌。`expire_time`字段用于自动失效过期的令牌,增强安全性。 + +**表注释**:`COMMENT='token 管理'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L451-L463) +- [AccessToken.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/AccessToken.java#L1-L65) + +### 作业调度表 (dv_job_schedule) +作业调度表定义了作业的自动化执行计划,支持定时和周期性任务。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识调度记录 | +| job_id | bigint(20) | 否 | 无 | 作业ID | 关联的作业ID | +| type | varchar(255) | 否 | 无 | 作业调度类型 | 调度的类型,如"CRON" | +| param | text | 是 | NULL | 调度参数 | JSON格式的调度参数 | +| cron_expression | varchar(255) | 是 | NULL | CRON 表达式 | 标准的CRON表达式 | +| status | tinyint(1) | 是 | NULL | 状态 | 调度是否启用,1为启用,0为禁用 | +| start_time | datetime | 是 | NULL | 开始时间 | 调度计划的开始时间 | +| end_time | datetime | 是 | NULL | 结束时间 | 调度计划的结束时间 | +| create_by | bigint(20) | 否 | 无 | 创建用户ID | 创建该调度的用户ID | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | 最后更新该调度的用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`cron_expression`字段直接存储CRON表达式,便于与调度框架集成。`status`字段控制调度的启停。 + +**表注释**:`COMMENT='规则作业调度'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L657-L675) +- [JobSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java#L1-L75) + +### SLA表 (dv_sla) +SLA表用于定义服务级别协议,将作业与告警策略关联起来。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识SLA记录 | +| workspace_id | bigint(20) | 否 | 无 | 工作空间ID | 所属工作空间的ID | +| name | varchar(255) | 否 | 无 | SLA 名字 | SLA的显示名称 | +| description | varchar(255) | 否 | 无 | 描述 | SLA的详细描述 | +| create_by | bigint(20) | 否 | 无 | 创建用户ID | 创建该SLA的用户ID | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | 最后更新该SLA的用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:该表作为SLA的元数据定义,具体的关联关系由`dv_sla_job`和`dv_sla_notification`等表实现。 + +**表注释**:`COMMENT='告警管理'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L704-L718) +- [Sla.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Sla.java#L1-L64) + +### 实体实例表 (dv_catalog_entity_instance) +实体实例表存储了元数据目录中的具体实体,如数据库、表、列等。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识实体实例记录 | +| uuid | varchar(64) | 否 | 无 | 实体实例UUID | 全局唯一标识符 | +| datasource_id | bigint(20) | 否 | 无 | 数据源ID | 所属数据源的ID | +| type | varchar(127) | 否 | 无 | 实体类型 | 如"database", "table", "column" | +| fully_qualified_name | varchar(255) | 否 | 无 | 全限定名 | 实体的完整路径名,如"db1.table1" | +| display_name | varchar(255) | 否 | 无 | 展示名字 | 实体的显示名称 | +| description | varchar(1024) | 是 | NULL | 描述 | 实体的描述信息 | +| properties | text | 是 | NULL | 其他参数 | JSON格式,存储实体的额外属性 | +| owner | varchar(255) | 是 | NULL | 拥有者 | 实体的负责人 | +| version | varchar(64) | 否 | 1.0 | 版本 | 实体的版本号 | +| status | varchar(255) | 是 | active | 实体状态 | 实体的状态,如"active"(启用)或"deleted"(已删除) | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | 最后更新该实体的用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`fully_qualified_name`字段使用`utf8mb4_bin`排序规则,确保大小写敏感的精确匹配。`status`字段用于软删除,避免数据丢失。`display_name`和`description`字段建立了全文索引,支持高效的搜索功能。 + +**表注释**:`COMMENT='实体实例'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L210-L233) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java#L1-L79) + +### 命令表 (dv_command) +命令表用于在系统组件间传递控制指令,如启动或停止作业。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识命令记录 | +| type | tinyint(4) | 否 | 0 | Command type | 命令类型:0为启动任务,1为停止任务 | +| parameter | text | 是 | NULL | json command parameters | JSON格式的命令参数 | +| job_execution_id | bigint(20) | 否 | 无 | task id | 关联的作业执行实例ID | +| execute_host | varchar(255) | 是 | NULL | job execute host | 命令应发送到的执行主机 | +| priority | int(11) | 是 | NULL | process instance priority | 优先级:0最高,1高,2中,3低,4最低 | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`type`字段使用`tinyint`存储枚举值,`priority`字段定义了任务的执行优先级。 + +**表注释**:`COMMENT='规则执行命令'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L398-L413) +- [Command.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Command.java#L1-L65) + +### 告警信息表 (dv_issue) +告警信息表存储了系统生成的告警事件。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识告警记录 | +| title | varchar(1024) | 是 | NULL | 告警标题 | 告警的标题 | +| content | text | 否 | 无 | 告警内容 | 告警的详细内容 | +| status | varchar(255) | 否 | 无 | good / bad alert | 告警状态,"good"表示恢复,"bad"表示异常 | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`status`字段用于区分告警和恢复事件。 + +**表注释**:`COMMENT='告警信息'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L484-L495) +- [Issue.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Issue.java#L1-L58) + +### 错误数据存储表 (dv_error_data_storage) +错误数据存储表定义了错误数据的存储位置和方式。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识存储记录 | +| name | varchar(255) | 否 | 无 | 存储名称 | 存储的显示名称 | +| type | varchar(255) | 否 | 无 | 存储类型 | 如"JDBC", "FILE"等 | +| param | text | 否 | 无 | 存储参数 | JSON格式的连接参数 | +| workspace_id | bigint(20) | 否 | 无 | 工作空间ID | 所属工作空间的ID | +| create_by | bigint(20) | 否 | 无 | 创建用户ID | 创建该存储的用户ID | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | 最后更新该存储的用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`name`和`workspace_id`组合成唯一索引,确保在同一工作空间内存储名称唯一。 + +**表注释**:`COMMENT='错误数据存储'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L465-L482) +- [ErrorDataStorage.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/ErrorDataStorage.java#L1-L64) + +### 租户表 (dv_tenant) +租户表定义了运行环境中的租户,用于资源隔离和代理执行。 + +| 字段名 | 数据类型 | 是否可空 | 默认值 | 字段说明 | 业务含义 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| id | bigint(20) | 否 | 无 | 主键ID | 唯一标识租户记录 | +| tenant | varchar(255) | 否 | 无 | 租户名 | 租户的名称 | +| workspace_id | bigint(20) | 否 | 无 | 工作空间ID | 所属工作空间的ID | +| create_by | bigint(20) | 否 | 无 | 创建用户ID | 创建该租户的用户ID | +| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 | 记录创建的时间 | +| update_by | bigint(20) | 否 | 无 | 更新用户ID | 最后更新该租户的用户ID | +| update_time | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 | 记录最后更新的时间 | + +**设计考虑**:`tenant`字段有唯一索引,确保租户名全局唯一。 + +**表注释**:`COMMENT='运行环境的租户'`,明确表的用途。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L772-L786) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java#L1-L60) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/SPI\345\216\237\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/SPI\345\216\237\347\220\206.md" new file mode 100644 index 00000000..cea938b7 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/SPI\345\216\237\347\220\206.md" @@ -0,0 +1,294 @@ +# SPI原理 + + +**本文档引用的文件** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [Prioritized.java](file://datavines-spi/src/main/java/io/datavines/spi/Prioritized.java) +- [ClassUtils.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/ClassUtils.java) +- [Holder.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/Holder.java) +- [ConnectorFactory.java](file://datavines-connector/connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [SqlMetric.java](file://datavines-metric/metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [SlasHandlerPlugin.java](file://datavines-notification/notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [NotificationManager.java](file://datavines-notification/notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [JdbcConnector.java](file://datavines-connector/connector-plugins/connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/notification-plugins/notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/connector-plugins/connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java) + + +## 目录 +1. [SPI机制概述](#spi机制概述) +2. [@SPI注解设计与使用](#spi注解设计与使用) +3. [服务发现与加载机制](#服务发现与加载机制) +4. [接口与实现映射管理](#接口与实现映射管理) +5. [运行时动态扩展实现](#运行时动态扩展实现) +6. [与其他SPI框架对比](#与其他spi框架对比) + +## SPI机制概述 + +DataVines的SPI(Service Provider Interface)机制是一种服务发现和插件化架构,旨在实现核心功能与插件模块的解耦。该机制允许系统在运行时动态发现和加载插件,从而支持灵活的功能扩展。SPI机制的核心设计目标是提供一种标准化的插件管理方式,使得开发者可以轻松地添加新的数据源连接器、质量度量指标、通知渠道等扩展功能,而无需修改核心代码。 + +该机制通过`@SPI`注解标识可扩展的接口,并利用`PluginLoader`类实现服务发现和实例化。整个SPI体系基于Java的类加载机制和反射技术,通过扫描特定目录下的配置文件来发现可用的插件实现。这种设计不仅提高了系统的可扩展性,还增强了模块间的松耦合性,使得各个功能模块可以独立开发和部署。 + +**本节来源** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L1-L51) + +## @SPI注解设计与使用 + +`@SPI`注解是DataVines SPI机制的核心标识,用于标记可扩展的接口。该注解定义在`io.datavines.spi.SPI`类中,具有以下特性: + +```java +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface SPI { + String value() default ""; +} +``` + +`@SPI`注解使用`RUNTIME`保留策略,确保在运行时可以通过反射访问。它只能应用于类型(类、接口或枚举),用于标识一个接口是可扩展的服务接口。注解的`value()`方法提供了一个可选的字符串参数,可用于指定默认实现的名称。 + +在实际使用中,任何希望作为SPI接口的接口都必须使用`@SPI`注解进行标记。例如,`ConnectorFactory`接口用于创建数据源连接器,被标记为SPI接口: + +```java +@SPI +public interface ConnectorFactory { + // 接口方法定义 +} +``` + +同样,`SqlMetric`接口用于定义数据质量度量指标,也使用`@SPI`注解: + +```java +@SPI +public interface SqlMetric { + // 接口方法定义 +} +``` + +通过这种方式,系统可以识别哪些接口是可扩展的,并在运行时查找其实现类。`@SPI`注解的设计遵循了Java原生SPI的思想,但提供了更丰富的功能和更好的性能。 + +**本节来源** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) +- [ConnectorFactory.java](file://datavines-connector/connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java#L1-L51) +- [SqlMetric.java](file://datavines-metric/metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L1-L42) + +## 服务发现与加载机制 + +DataVines的SPI机制通过`PluginLoader`类实现服务发现和加载。该类负责扫描`META-INF/plugins`目录下的配置文件,解析并加载可用的插件实现。服务发现的工作流程如下: + +1. **类加载器获取**:`PluginLoader`首先通过`findClassLoader()`方法获取合适的类加载器,优先使用线程上下文类加载器,如果不可用则回退到系统类加载器。 + +2. **配置文件扫描**:系统扫描`META-INF/plugins`目录下以SPI接口全限定名为文件名的配置文件。例如,对于`SlasHandlerPlugin`接口,会查找`META-INF/plugins/io.datavines.notification.api.spi.SlasHandlerPlugin`文件。 + +3. **配置文件解析**:每个配置文件包含插件名称与实现类全限定名的映射,格式为`name=fully.qualified.class.name`。`PluginLoader`读取这些配置并解析出可用的插件实现。 + +4. **类加载与验证**:加载配置文件中指定的实现类,并验证其实现了对应的SPI接口。如果验证失败,将抛出`IllegalStateException`异常。 + +5. **缓存管理**:为了提高性能,`PluginLoader`使用多个并发映射(ConcurrentMap)来缓存已加载的类、实例和配置信息,避免重复加载和解析。 + +```mermaid +flowchart TD +Start([开始]) --> FindClassLoader["获取类加载器"] +FindClassLoader --> ScanConfig["扫描META-INF/plugins配置文件"] +ScanConfig --> ParseConfig["解析配置文件内容"] +ParseConfig --> LoadClass["加载实现类"] +LoadClass --> ValidateClass["验证类实现SPI接口"] +ValidateClass --> CacheClass["缓存类信息"] +CacheClass --> End([结束]) +ParseConfig --> |配置格式错误| HandleError["处理解析错误"] +LoadClass --> |类加载失败| HandleError +ValidateClass --> |验证失败| HandleError +HandleError --> End +``` + +**图示来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L347-L364) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L371-L402) + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L51-L487) +- [ClassUtils.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/ClassUtils.java#L1-L51) + +## 接口与实现映射管理 + +DataVines的SPI机制通过`PluginLoader`类管理接口与实现类的映射关系。这种映射管理是SPI机制的核心功能之一,确保了系统能够正确地将接口调用路由到相应的实现类。 + +映射关系的管理主要通过以下数据结构实现: + +1. **cachedClasses**:`ConcurrentMap>`类型的缓存,存储插件名称到实现类的映射。这个缓存是线程安全的,允许多个线程同时访问。 + +2. **cachedNames**:`ConcurrentMap, String>`类型的缓存,存储实现类到插件名称的映射。这实现了双向映射,便于在运行时查询。 + +3. **cachedInstances**:`ConcurrentMap>`类型的缓存,存储插件名称到实例的映射。`Holder`类用于确保实例的延迟加载和线程安全。 + +默认实现的选择策略基于以下规则: + +1. **配置文件优先**:如果在配置文件中指定了插件名称,则使用该名称作为默认实现。 + +2. **类名推断**:如果配置文件中没有指定名称,系统会根据实现类的类名推断默认名称。通常,系统会移除接口名称后缀并转换为小写。 + +3. **优先级排序**:当需要获取所有支持的插件实例时,系统会根据`Prioritized`接口的优先级进行排序。优先级高的插件会排在前面。 + +```mermaid +classDiagram +class PluginLoader { ++Class type ++ConcurrentMap, String> cachedNames ++Holder>> cachedClasses ++ConcurrentMap> cachedInstances ++getPluginClasses() Map~String, Class~? ++loadPluginClasses() Map~String, Class~? ++getOrCreatePlugin(String) T +} +class Holder~T~ { +-volatile T value ++set(T) ++get() T +} +PluginLoader --> Holder~T~ : "使用" +PluginLoader --> Map : "管理" +PluginLoader --> ConcurrentMap : "使用" +``` + +**图示来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L63-L70) +- [Holder.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/Holder.java#L1-L34) + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L63-L450) +- [Holder.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/Holder.java#L1-L34) + +## 运行时动态扩展实现 + +DataVines的SPI机制支持运行时动态扩展,这是其核心优势之一。通过`PluginLoader`提供的API,系统可以在运行时动态加载、创建和管理插件实例,实现了核心功能与插件模块的完全解耦。 + +运行时动态扩展的主要实现方式包括: + +1. **延迟实例化**:插件实例采用延迟加载策略,只有在首次请求时才会创建。这通过`Holder`类实现,确保了线程安全和性能优化。 + +2. **单例模式**:`getOrCreatePlugin()`方法确保每个插件名称对应一个单例实例,避免了重复创建和资源浪费。 + +3. **动态加载**:`getNewPlugin()`方法允许创建新的插件实例,适用于需要多个实例的场景。 + +4. **插件替换**:`addOrReplacePlugin()`方法允许在运行时添加或替换插件实现,主要用于测试场景。 + +在实际应用中,`NotificationManager`类展示了SPI机制的典型使用模式: + +```java +public class NotificationManager { + private final Set supportedPlugins; + + public NotificationManager(){ + supportedPlugins = PluginLoader + .getPluginLoader(SlasHandlerPlugin.class) + .getSupportedPlugins(); + } + + public SlaNotificationResult notify(SlaNotificationMessage message, Map> config){ + for (Map.Entry> entry: config.entrySet()) { + String type = entry.getKey().getType(); + if (!supportedPlugins.contains(type)) { + throw new DataVinesException("sender type not support of "+ type); + } + SlasHandlerPlugin handlerPlugin = PluginLoader + .getPluginLoader(SlasHandlerPlugin.class) + .getOrCreatePlugin(type); + // 使用插件实例 + } + } +} +``` + +这种设计使得通知系统可以支持多种通知渠道(如邮件、钉钉、企业微信等),而无需在核心代码中硬编码这些渠道的实现。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Manager as "NotificationManager" +participant Loader as "PluginLoader" +participant Plugin as "具体插件实现" +Client->>Manager : 发送通知请求 +Manager->>Loader : getSupportedPlugins() +Loader-->>Manager : 返回支持的插件列表 +Manager->>Loader : getOrCreatePlugin(type) +Loader->>Loader : 检查实例缓存 +alt 实例不存在 +Loader->>Loader : 加载类并创建实例 +Loader->>Loader : 缓存实例 +end +Loader-->>Manager : 返回插件实例 +Manager->>Plugin : 调用notify()方法 +Plugin-->>Manager : 返回通知结果 +Manager-->>Client : 返回最终结果 +``` + +**图示来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L135-L188) +- [NotificationManager.java](file://datavines-notification/notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java#L39-L71) + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L135-L230) +- [NotificationManager.java](file://datavines-notification/notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java#L1-L71) + +## 与其他SPI框架对比 + +DataVines的SPI机制与Java原生SPI和Dubbo SPI相比,具有以下特点和优势: + +### 与Java原生SPI对比 + +| 特性 | Java原生SPI | DataVines SPI | +|------|------------|---------------| +| **性能** | 每次调用`ServiceLoader.load()`都会重新扫描和加载,性能较差 | 使用缓存机制,避免重复扫描和加载,性能更优 | +| **实例化** | 每次调用`iterator()`都会创建新实例 | 支持单例模式,通过`getOrCreatePlugin()`实现延迟单例 | +| **扩展性** | 仅支持通过`META-INF/services`发现实现 | 支持自定义插件目录`META-INF/plugins`,更灵活 | +| **错误处理** | 异常处理简单,不利于调试 | 提供详细的异常信息和可能原因,便于问题排查 | + +### 与Dubbo SPI对比 + +| 特性 | Dubbo SPI | DataVines SPI | +|------|---------|---------------| +| **复杂性** | 功能丰富但复杂,包含AOP、IOC等高级特性 | 设计简洁,专注于核心的插件发现和加载功能 | +| **依赖** | 依赖Dubbo框架的其他组件 | 独立实现,不依赖外部框架 | +| **配置格式** | 支持复杂的配置语法 | 使用简单的`name=class`格式,易于理解和维护 | +| **学习曲线** | 较陡峭,需要理解Dubbo的SPI设计理念 | 平缓,易于理解和使用 | + +### DataVines SPI设计优势 + +1. **简洁性**:相比Dubbo SPI,DataVines SPI去除了AOP、IOC等复杂特性,专注于提供稳定可靠的插件发现和加载功能。 + +2. **性能优化**:通过多级缓存机制(类缓存、实例缓存)显著提高了运行时性能,避免了重复的类加载和实例化开销。 + +3. **线程安全**:使用`ConcurrentMap`和`volatile`等机制确保了多线程环境下的安全性。 + +4. **易用性**:API设计简洁明了,`getPluginLoader()`、`getOrCreatePlugin()`等方法易于理解和使用。 + +5. **灵活性**:支持运行时动态添加和替换插件,虽然`addOrReplacePlugin()`方法标记为`@deprecated`,但仍为测试和特殊场景提供了可能性。 + +6. **健壮性**:提供了详细的错误处理和异常信息,帮助开发者快速定位和解决问题。 + +```mermaid +graph TD +A[Java原生SPI] --> |缺点| B[性能差] +A --> |缺点| C[无缓存] +A --> |缺点| D[简单错误处理] +E[Dubbo SPI] --> |缺点| F[过于复杂] +E --> |缺点| G[依赖框架] +E --> |缺点| H[学习曲线陡] +I[DataVines SPI] --> |优点| J[高性能] +I --> |优点| K[简洁设计] +I --> |优点| L[线程安全] +I --> |优点| M[易用性] +I --> |优点| N[灵活性] +I --> |优点| O[健壮性] +``` + +**图示来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L59-L62) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L135-L188) + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L1-L487) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) +- [Prioritized.java](file://datavines-spi/src/main/java/io/datavines/spi/Prioritized.java#L1-L71) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/\346\217\222\344\273\266\345\212\240\350\275\275\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/\346\217\222\344\273\266\345\212\240\350\275\275\346\234\272\345\210\266.md" new file mode 100644 index 00000000..6bda70cb --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/\346\217\222\344\273\266\345\212\240\350\275\275\346\234\272\345\210\266.md" @@ -0,0 +1,208 @@ +# 插件加载机制 + + +**本文档中引用的文件** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [Prioritized.java](file://datavines-spi/src/main/java/io/datavines/spi/Prioritized.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [ClassUtils.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/ClassUtils.java) +- [MysqlConnectorFactory.java](file://datavines-connector/ datavines-connector-plugins/ datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnectorFactory.java) +- [ColumnAvg.java](file://datavines-metric/ datavines-metric-plugins/ datavines-metric-column-avg/src/main/java/io/datavines/metric/plugin/ColumnAvg.java) +- [ConnectorFactory.java](file://datavines-connector/ datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [SqlMetric.java](file://datavines-metric/ datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) + + +## 目录 +1. [引言](#引言) +2. [插件加载器架构](#插件加载器架构) +3. [类加载过程](#类加载过程) +4. [实例化与反射机制](#实例化与反射机制) +5. [插件缓存机制](#插件缓存机制) +6. [类加载器隔离策略](#类加载器隔离策略) +7. [插件优先级实现](#插件优先级实现) +8. [异常处理与错误恢复](#异常处理与错误恢复) +9. [总结](#总结) + +## 引言 +DataVines插件加载器(PluginLoader)是系统扩展机制的核心组件,它基于SPI(Service Provider Interface)设计模式实现插件的动态加载与管理。该机制允许系统在运行时发现、加载和实例化插件实现,从而支持功能的灵活扩展。本文将深入剖析PluginLoader的内部工作机制,涵盖类加载、实例化、缓存、隔离、优先级排序及异常处理等关键方面。 + +## 插件加载器架构 + +```mermaid +classDiagram +class PluginLoader~T~ { ++static getPluginLoader(Class type) PluginLoader~T~ ++getOrCreatePlugin(String name) T ++getLoadedPlugin(String name) T ++getSupportedPlugins() Set~String~ ++getSupportedPluginInstances() Set~T~ +-loadPluginClasses() Map~String, Class~? +-loadResource(Map~String, Class~?, ClassLoader, URL) +-loadClass(Map~String, Class~?, URL, Class~?, String) +-createPlugin(String name) T +} +class SPI { ++String value() +} +class Prioritized { ++static final Comparator~Object~ COMPARATOR ++int MAX_PRIORITY ++int MIN_PRIORITY ++int NORMAL_PRIORITY ++int getPriority() ++int compareTo(Prioritized that) +} +class PluginLoader <|-- SPI : "注解" +class PluginLoader <|-- Prioritized : "实现" +PluginLoader --> ClassUtils : "使用" +PluginLoader --> Holder : "使用" +PluginLoader --> UnsafeStringWriter : "使用" +``` + +**图示来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [Prioritized.java](file://datavines-spi/src/main/java/io/datavines/spi/Prioritized.java) +- [ClassUtils.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/ClassUtils.java) + +## 类加载过程 + +DataVines插件加载器的类加载过程遵循标准的SPI机制,但进行了增强和优化。整个过程始于`getPluginLoader`方法,该方法通过双重检查锁定模式确保每个插件接口类型仅对应一个PluginLoader实例,实现了线程安全的单例管理。 + +类加载的核心在于从classpath中定位并解析插件描述文件。PluginLoader定义了固定的插件目录`META-INF/plugins/`,并根据插件接口的全限定名(如`io.datavines.connector.api.ConnectorFactory`)构造文件路径。通过`findClassLoader`方法获取合适的类加载器(优先使用线程上下文类加载器),然后调用`getResources`方法查找所有匹配的资源文件。 + +对于每一个找到的资源文件(URL),系统会创建`BufferedReader`进行逐行读取。在解析过程中,会忽略以`#`开头的注释行和空行。每一行有效的配置采用`name=implementation-class`的格式。例如,在`datavines-connector-mysql`模块中,`META-INF/plugins/io.datavines.connector.api.ConnectorFactory`文件包含`mysql=io.datavines.connector.plugin.MysqlConnectorFactory`这样的配置。 + +解析出实现类的全限定名后,通过`Class.forName`方法在指定的类加载器上下文中加载该类。加载后的类会经过严格的验证:必须是具体类(非接口、非抽象类),并且必须实现PluginLoader所管理的接口类型。验证通过后,类与名称的映射关系会被缓存到`cachedClasses`中,为后续的实例化做准备。 + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L322-L398) +- [ClassUtils.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/ClassUtils.java#L27-L47) + +## 实例化与反射机制 + +插件的实例化过程是延迟的,即只有在首次请求某个插件实例时才会进行创建,这有助于提升系统启动性能。实例化主要通过`getOrCreatePlugin`方法实现,该方法结合了双重检查锁定和`Holder`模式来保证线程安全。 + +当调用`getOrCreatePlugin("mysql")`时,系统首先检查`cachedInstances`缓存中是否存在名为"mysql"的实例持有者(Holder)。如果不存在,则创建一个新的`Holder`并放入缓存。随后,通过`holder.get()`尝试获取实例。如果实例为`null`,则进入同步块(使用`pluginLock`锁),再次检查实例是否存在(防止并发创建),然后调用`createPlugin`方法。 + +`createPlugin`方法是反射调用的核心。它首先从`getPluginClasses()`获取已加载的类映射,找到与名称"mysql"对应的`Class`对象(即`MysqlConnectorFactory.class`)。接着,通过`clazz.newInstance()`(或更现代的`clazz.getDeclaredConstructor().newInstance()`)使用反射创建该类的新实例。为了优化性能,新创建的实例会被放入一个全局的`PLUGIN_INSTANCES`缓存中,确保同一个实现类在JVM中只存在一个实例(单例模式)。最后,实例被设置到`Holder`中并返回。 + +值得注意的是,`getNewPlugin`方法提供了另一种实例化方式,它每次都会创建一个新的实例,不使用全局缓存,适用于需要多实例的场景。 + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L171-L203) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L290-L305) + +## 插件缓存机制 + +DataVines插件加载器设计了多层次的缓存机制,以显著提高多次获取同一插件实例的性能。 + +第一层是**类映射缓存**(`cachedClasses`),这是一个`Holder>>`类型的缓存。它存储了插件名称到其实现类的映射。`Holder`包装器允许在并发环境下安全地初始化和设置缓存。这个缓存只在首次调用`getPluginClasses()`时加载一次,之后所有对插件类的查询都直接从内存中获取,避免了重复的文件I/O和类加载操作。 + +第二层是**实例缓存**(`cachedInstances`),这是一个`ConcurrentMap>`。它为每个插件名称维护一个`Holder`,而`Holder`内部持有实际的插件实例。这种设计巧妙地将实例的创建(可能耗时)与获取分离。`getOrCreatePlugin`方法的调用者看到的是一个快速的`holder.get()`操作,而真正的实例化过程在同步块内完成,且只执行一次。 + +第三层是**全局实例缓存**(`PLUGIN_INSTANCES`),这是一个静态的`ConcurrentMap, Object>`。它确保了同一个插件实现类(如`MysqlConnectorFactory`)在整个JVM中只存在一个实例,实现了单例模式,减少了内存占用。 + +此外,还有一个**名称缓存**(`cachedNames`),用于存储类到其默认名称的映射,加速`getPluginName`方法的调用。 + +```mermaid +flowchart TD +A[getOrCreatePlugin("mysql")] --> B{cachedInstances
有Holder吗?} +B --> |否| C[创建新Holder
放入cachedInstances] +B --> |是| D[获取现有Holder] +C --> D +D --> E{Holder有实例吗?} +E --> |否| F[获取pluginLock锁] +F --> G{Holder有实例吗?} +G --> |否| H[createPlugin] +G --> |是| I[返回实例] +H --> J[clazz.newInstance()] +J --> K[放入PLUGIN_INSTANCES] +K --> L[设置到Holder] +L --> I +E --> |是| I +I --> M[返回实例] +style F fill:#f9f,stroke:#333 +style H fill:#f9f,stroke:#333 +``` + +**图示来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L69-L71) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L61-L62) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L65-L66) + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L61-L71) + +## 类加载器隔离策略 + +DataVines通过精心设计的类加载器策略来确保不同插件之间的类路径不会相互干扰。其核心在于`findClassLoader`方法。 + +该方法首先尝试获取当前线程的上下文类加载器(`Thread.currentThread().getContextClassLoader()`)。这是Java EE和框架中常用的做法,可以确保插件加载发生在正确的应用上下文中。如果获取失败(例如在简单的Java SE环境中),则退而使用`PluginLoader`类本身的类加载器(`clazz.getClassLoader()`)。 + +这种策略的关键优势在于,它允许插件的加载上下文与定义插件接口的`datavines-spi`模块分离。例如,当一个Web应用(拥有自己的WebAppClassLoader)使用DataVines时,插件将通过Web应用的类加载器来加载,从而能够访问Web应用的classpath,而不会与容器的系统类加载器发生冲突。 + +虽然DataVines目前没有为每个插件使用独立的类加载器(如OSGi那样),但通过依赖于调用上下文的类加载器,它在大多数应用场景下有效地实现了类路径的隔离,避免了常见的`ClassNotFoundException`和`NoClassDefFoundError`问题。 + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L120-L122) +- [ClassUtils.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/ClassUtils.java#L27-L47) + +## 插件优先级实现 + +DataVines通过`Prioritized`接口实现了插件的优先级排序机制。任何插件实现类都可以实现`Prioritized`接口,以表明其优先级。 + +`Prioritized`接口定义了三个常量:`MAX_PRIORITY`(最高优先级)、`MIN_PRIORITY`(最低优先级)和`NORMAL_PRIORITY`(普通优先级,值为0)。它提供了一个默认方法`getPriority()`,返回`NORMAL_PRIORITY`。插件实现类可以重写此方法来返回一个整数值,数值越小表示优先级越高。 + +该机制的核心是`Prioritized`接口中定义的静态`COMPARATOR`比较器。这个比较器非常智能,它能够处理三种情况: +1. 如果一个对象实现了`Prioritized`而另一个没有,则实现了接口的对象优先级更高。 +2. 如果两个对象都实现了`Prioritized`,则根据它们的`getPriority()`返回值进行比较。 +3. 如果两个对象都没有实现`Prioritized`,则认为它们优先级相同。 + +这个比较器在`getSupportedPluginInstances`方法中被使用。该方法会获取所有支持的插件实例,并使用`Prioritized.COMPARATOR`对其进行排序,最终返回一个按优先级排序的`LinkedHashSet`。这使得系统可以根据优先级选择最合适的实现,例如在有多个可用的数据源连接器时,优先选择高优先级的实现。 + +```mermaid +sequenceDiagram +participant Client +participant PluginLoader +participant Comparator +participant PluginA +participant PluginB +Client->>PluginLoader : getSupportedPluginInstances() +PluginLoader->>PluginLoader : 获取所有插件实例 +PluginLoader->>Comparator : instances.sort(COMPARATOR) +Comparator->>PluginA : getPriority() +Comparator->>PluginB : getPriority() +alt PluginA优先级更高 +Comparator-->>PluginLoader : 返回排序结果 +else PluginB优先级更高 +Comparator-->>PluginLoader : 返回排序结果 +end +PluginLoader-->>Client : 返回排序后的实例集合 +``` + +**图示来源** +- [Prioritized.java](file://datavines-spi/src/main/java/io/datavines/spi/Prioritized.java#L28-L40) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L228-L229) + +**本节来源** +- [Prioritized.java](file://datavines-spi/src/main/java/io/datavines/spi/Prioritized.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L228) + +## 异常处理与错误恢复机制 + +PluginLoader在插件加载的各个阶段都实现了完善的异常处理和错误恢复机制,以保证系统的健壮性。 + +在**类加载阶段**,`loadResource`和`loadClass`方法都使用了try-catch块来捕获`Throwable`。当加载某个具体的实现类失败时(例如类不存在或依赖缺失),系统会创建一个`IllegalStateException`,并将其以类名作为键存储在`exceptions`映射中。这不会导致整个插件加载过程的中断,系统会继续尝试加载文件中的其他实现类,实现了“失败隔离”。 + +在**实例化阶段**,`createPlugin`和`getNewPlugin`方法同样捕获`Throwable`。如果实例化失败,会抛出一个包含详细错误信息的`IllegalStateException`。`findException`方法是错误恢复的关键。当用户请求一个不存在的插件时,该方法不仅会报告“找不到插件”,还会遍历`exceptions`映射,列出所有加载失败的可能原因,极大地便利了问题排查。 + +此外,`hasPlugin`和`containsPlugin`等方法提供了非破坏性的查询方式,允许调用者在不触发实例化的情况下检查插件是否存在,从而避免了不必要的异常抛出。 + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L392-L395) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L303-L305) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L265-L286) + +## 总结 +DataVines的插件加载器(PluginLoader)是一个设计精良、功能完备的SPI实现。它通过标准化的`META-INF/plugins`配置、延迟实例化、多层次缓存和线程安全控制,实现了高效且可靠的插件管理。其类加载器策略确保了良好的隔离性,`Prioritized`接口支持灵活的优先级排序,而全面的异常处理机制则保障了系统的稳定性。这一机制是DataVines能够支持多种数据源、计算引擎和通知方式等丰富插件生态的技术基石。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/\346\217\222\344\273\266\345\274\200\345\217\221\346\214\207\345\215\227.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/\346\217\222\344\273\266\345\274\200\345\217\221\346\214\207\345\215\227.md" new file mode 100644 index 00000000..3052b852 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/\346\217\222\344\273\266\345\274\200\345\217\221\346\214\207\345\215\227.md" @@ -0,0 +1,403 @@ +# 插件开发指南 + + +**本文档中引用的文件** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [TableRowCountMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/table/TableRowCountMetric.java) +- [DingtalkNotificationPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingtalkNotificationPlugin.java) + + +## 目录 +1. [简介](#简介) +2. [插件架构概述](#插件架构概述) +3. [数据源插件开发](#数据源插件开发) +4. [指标插件开发](#指标插件开发) +5. [告警通道插件开发](#告警通道插件开发) +6. [插件配置与参数传递](#插件配置与参数传递) +7. [测试实践](#测试实践) +8. [打包与部署](#打包与部署) +9. [验证与调试](#验证与调试) + +## 简介 +DataVines 是一个数据质量监控平台,支持通过插件机制扩展其功能。本指南详细介绍了如何开发数据源插件、指标插件和告警通道插件。我们将以 JDBC 数据源、表行数指标和钉钉告警通道为例,演示从接口实现到服务注册的完整开发流程。 + +**Section sources** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L1-L487) + +## 插件架构概述 +DataVines 使用 SPI(Service Provider Interface)机制实现插件化架构。核心组件包括: + +1. **SPI 注解**:标记接口为可扩展插件点 +2. **PluginLoader**:负责插件的加载、实例化和管理 +3. **META-INF/plugins**:存放插件配置文件的目录 + +插件加载流程如下: +```mermaid +flowchart TD +Start([启动]) --> LoadSPI["加载 SPI 注解接口"] +LoadSPI --> FindConfig["查找 META-INF/plugins 配置文件"] +FindConfig --> ReadConfig["读取配置文件中的实现类"] +ReadConfig --> LoadClass["加载实现类"] +LoadClass --> Instantiate["实例化插件"] +Instantiate --> Register["注册到 PluginLoader"] +Register --> End([完成]) +``` + +**Diagram sources** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L346-L364) + +**Section sources** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L1-L487) + +## 数据源插件开发 +数据源插件需要实现 `Connector` 接口,该接口定义了与数据源交互的基本方法。 + +### 实现 Connector 接口 +```java +@SPI("jdbc") +public interface Connector { + DataSourceClient getDataSourceClient(Configurations configurations); + Executor getExecutor(Configurations configurations); + Dialect getDialect(); + StatementParser getStatementParser(); + StatementSplitter getStatementSplitter(); + TypeConverter getTypeConverter(); + ParameterConverter getParameterConverter(); + ResponseConverter getResponseConverter(); +} +``` + +### 创建 JDBC 数据源实现 +以 `JdbcConnector` 为例,实现步骤如下: + +1. 创建实现类并继承 `JdbcConnector` +2. 实现必要的方法 +3. 提供相应的配置构建器 + +```mermaid +classDiagram +class Connector { ++getDataSourceClient(Configurations) DataSourceClient ++getExecutor(Configurations) Executor ++getDialect() Dialect ++getStatementParser() StatementParser ++getStatementSplitter() StatementSplitter ++getTypeConverter() TypeConverter ++getParameterConverter() ParameterConverter ++getResponseConverter() ResponseConverter +} +class JdbcConnector { ++getDataSourceClient(Configurations) JdbcDataSourceClient ++getExecutor(Configurations) BaseJdbcExecutor ++getDialect() JdbcDialect ++getStatementParser() DefaultStatementParser ++getStatementSplitter() DefaultStatementSplitter ++getTypeConverter() JdbcTypeConverter ++getParameterConverter() JdbcParameterConverter ++getResponseConverter() JdbcResponseConverter +} +class JdbcConfigBuilder { ++build(Configurations) JdbcOptions +} +JdbcConnector --> JdbcConfigBuilder : "使用" +Connector <|-- JdbcConnector : "实现" +``` + +**Diagram sources** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L20) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L1-L50) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java#L1-L30) + +**Section sources** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L50) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L1-L100) + +## 指标插件开发 +指标插件需要实现 `SqlMetric` 接口,用于定义数据质量检查的指标。 + +### 实现 SqlMetric 接口 +```java +public interface SqlMetric extends MetricValidator { + String getName(); + String getSql(); + Map getProperties(); + void setProperties(Map properties); + MetricType getMetricType(); + MetricDimension getMetricDimension(); + ResultFormula getResultFormula(); + ExpectedValue getExpectedValue(); +} +``` + +### 创建表行数指标实现 +以 `TableRowCountMetric` 为例,实现步骤如下: + +1. 创建实现类并实现 `SqlMetric` 接口 +2. 定义指标名称、SQL 查询语句 +3. 配置预期值验证器 + +```mermaid +classDiagram +class SqlMetric { ++getName() String ++getSql() String ++getProperties() Map~String, Object~ ++setProperties(Map~String, Object~) void ++getMetricType() MetricType ++getMetricDimension() MetricDimension ++getResultFormula() ResultFormula ++getExpectedValue() ExpectedValue +} +class TableRowCountMetric { +-name : String +-sql : String +-properties : Map~String, Object~ +-metricType : MetricType +-metricDimension : MetricDimension +-resultFormula : ResultFormula +-expectedValue : ExpectedValue ++getName() String ++getSql() String ++getProperties() Map~String, Object~ ++setProperties(Map~String, Object~) void ++getMetricType() MetricType ++getMetricDimension() MetricDimension ++getResultFormula() ResultFormula ++getExpectedValue() ExpectedValue +} +class ExpectedValue { ++validate(Object) boolean ++getExpectedValue() Object +} +class ResultFormula { ++calculate(Object) Object +} +SqlMetric <|-- TableRowCountMetric : "实现" +TableRowCountMetric --> ExpectedValue : "包含" +TableRowCountMetric --> ResultFormula : "包含" +``` + +**Diagram sources** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L1-L30) +- [TableRowCountMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/table/TableRowCountMetric.java#L1-L50) + +**Section sources** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L1-L50) +- [TableRowCountMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/table/TableRowCountMetric.java#L1-L100) + +## 告警通道插件开发 +告警通道插件需要实现 `SlasHandlerPlugin` 接口,用于发送质量检查结果通知。 + +### 实现 SlasHandlerPlugin 接口 +```java +public interface SlasHandlerPlugin { + boolean send(NotificationMessage notificationMessage); + String getName(); + List getConfigItems(); +} +``` + +### 创建钉钉告警通道实现 +以 `DingtalkNotificationPlugin` 为例,实现步骤如下: + +1. 创建实现类并实现 `SlasHandlerPlugin` 接口 +2. 实现消息发送逻辑 +3. 定义配置项 + +```mermaid +classDiagram +class SlasHandlerPlugin { ++send(NotificationMessage) boolean ++getName() String ++getConfigItems() ConfigItem[] +} +class DingtalkNotificationPlugin { +-name : String +-configItems : ConfigItem[] ++send(NotificationMessage) boolean ++getName() String ++getConfigItems() ConfigItem[] +-sendToDingtalk(String) boolean +} +class NotificationMessage { +-title : String +-content : String +-type : String +} +class ConfigItem { +-name : String +-type : String +-required : boolean +-defaultValue : String +-placeholder : String +} +SlasHandlerPlugin <|-- DingtalkNotificationPlugin : "实现" +DingtalkNotificationPlugin --> NotificationMessage : "使用" +DingtalkNotificationPlugin --> ConfigItem : "包含" +``` + +**Diagram sources** +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java#L1-L15) +- [DingtalkNotificationPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingtalkNotificationPlugin.java#L1-L40) + +**Section sources** +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java#L1-L20) +- [DingtalkNotificationPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingtalkNotificationPlugin.java#L1-L80) + +## 插件配置与参数传递 +插件通过 `META-INF/plugins` 目录下的配置文件进行注册。 + +### 创建服务配置文件 +在 `META-INF/plugins` 目录下创建文件,文件名为接口的全限定名: +``` +io.datavines.connector.api.Connector +``` + +文件内容为实现类的全限定名: +``` +jdbc=io.datavines.connector.plugin.JdbcConnector +mysql=io.datavines.connector.plugin.MysqlConnector +postgresql=io.datavines.connector.plugin.PostgresqlConnector +``` + +### 参数配置传递机制 +插件参数通过 `Configurations` 对象传递,开发人员可以在插件中读取这些配置: + +```java +public class JdbcConnector implements Connector { + @Override + public DataSourceClient getDataSourceClient(Configurations configurations) { + String host = configurations.getString("host"); + int port = configurations.getInt("port"); + String username = configurations.getString("username"); + String password = configurations.getString("password"); + // 使用配置创建数据源客户端 + return new JdbcDataSourceClient(host, port, username, password); + } +} +``` + +**Section sources** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L371-L398) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L50-L80) + +## 测试实践 +为确保插件的稳定性和兼容性,建议进行单元测试和集成测试。 + +### 单元测试 +测试插件的基本功能和边界条件: + +```java +@Test +public void testJdbcConnectorCreation() { + Configurations configurations = new Configurations(); + configurations.setString("host", "localhost"); + configurations.setInt("port", 3306); + configurations.setString("username", "test"); + configurations.setString("password", "test"); + + JdbcConnector connector = new JdbcConnector(); + DataSourceClient client = connector.getDataSourceClient(configurations); + + assertNotNull(client); + assertTrue(client instanceof JdbcDataSourceClient); +} +``` + +### 集成测试 +测试插件在实际环境中的表现: + +```java +@Test +public void testTableRowCountMetricExecution() { + // 设置测试数据库 + // 执行指标检查 + // 验证结果 + assertTrue(result.getActualValue() > 0); +} +``` + +**Section sources** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L1-L100) +- [TableRowCountMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/table/TableRowCountMetric.java#L1-L100) + +## 打包与部署 +插件开发完成后,需要正确打包并部署到 DataVines 环境中。 + +### Maven 配置 +在 `pom.xml` 中配置插件模块: + +```xml +io.datavines +datavines-connector-mysql +1.0.0 +jar + + + + io.datavines + datavines-connector-api + ${project.version} + + +``` + +### 打包步骤 +1. 编译代码:`mvn clean compile` +2. 打包:`mvn package` +3. 将生成的 JAR 文件复制到 DataVines 的插件目录 + +### 部署位置 +将插件 JAR 文件放置在以下目录: +``` +datavines/lib/plugins/ +``` + +**Section sources** +- [pom.xml](file://datavines-connector/datavines-connector-mysql/pom.xml#L1-L50) + +## 验证与调试 +部署完成后,需要验证插件是否正确加载和运行。 + +### 验证插件加载 +启动 DataVines 服务,检查日志中是否有插件加载信息: + +``` +INFO PluginLoader:123 - Load plugin: jdbc -> io.datavines.connector.plugin.JdbcConnector +INFO PluginLoader:123 - Load plugin: table_row_count -> io.datavines.metric.plugin.table.TableRowCountMetric +INFO PluginLoader:123 - Load plugin: dingtalk -> io.datavines.notification.plugin.dingtalk.DingtalkNotificationPlugin +``` + +### 调试技巧 +1. 检查 `META-INF/plugins` 目录下的配置文件是否正确 +2. 确认实现类的全限定名是否正确 +3. 查看日志中的错误信息 +4. 使用调试模式启动服务 + +```mermaid +flowchart TD +Start([开始验证]) --> CheckConfig["检查 META-INF/plugins 配置"] +CheckConfig --> CheckClass["验证实现类全限定名"] +CheckClass --> StartService["启动 DataVines 服务"] +StartService --> CheckLog["查看日志输出"] +CheckLog --> VerifyPlugin["确认插件加载信息"] +VerifyPlugin --> TestFunction["测试插件功能"] +TestFunction --> End([验证完成]) +``` + +**Diagram sources** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L171-L188) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) + +**Section sources** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L1-L487) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/\346\217\222\344\273\266\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/\346\217\222\344\273\266\346\234\272\345\210\266.md" new file mode 100644 index 00000000..2ae85cea --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\217\222\344\273\266\346\234\272\345\210\266/\346\217\222\344\273\266\346\234\272\345\210\266.md" @@ -0,0 +1,12 @@ + +# 插件机制 + + +**本文档引用的文件** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [Prioritized.java](file://datavines-spi/src/main/java/io/datavines/spi/Prioritized.java) +- [ClassUtils.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/ClassUtils.java) +- [Holder.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/Holder.java) +- [UnsafeStringWriter.java](file://datavines-spi/src/main/java/io/datavines/spi/utils/UnsafeStringWriter.java) +- [ConnectorFactory.java](file://datavines-connector/da \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\344\273\273\345\212\241\350\260\203\345\272\246/\344\273\273\345\212\241\350\260\203\345\272\246.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\344\273\273\345\212\241\350\260\203\345\272\246/\344\273\273\345\212\241\350\260\203\345\272\246.md" new file mode 100644 index 00000000..5982434d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\344\273\273\345\212\241\350\260\203\345\272\246/\344\273\273\345\212\241\350\260\203\345\272\246.md" @@ -0,0 +1,318 @@ +# 任务调度 + + +**本文档引用的文件** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [CommonTaskFailover.java](file://datavines-server\src\main\java\io\datavines\server\scheduler\CommonTaskFailover.java) +- [Register.java](file://datavines-server\src\main\java\io\datavines\server\registry\Register.java) +- [JobScheduleType.java](file://datavines-server\src\main\java\io\datavines\server\enums\JobScheduleType.java) +- [ScheduleJobType.java](file://datavines-server\src\main\java\io\datavines\server\enums\ScheduleJobType.java) +- [CommonTaskType.java](file://datavines-server\src\main\java\io\datavines\server\enums\CommonTaskType.java) + + +## 目录 +1. [引言](#引言) +2. [基于Quartz的任务调度机制](#基于quartz的任务调度机制) +3. [ScheduleJobInfo元数据封装](#schedulejobinfo元数据封装) +4. [DataQualityScheduleJob执行逻辑](#dataqualityschedulejob执行逻辑) +5. [JobScheduler任务生命周期管理](#jobscheduler任务生命周期管理) +6. [高可用设计与故障转移机制](#高可用设计与故障转移机制) +7. [调度任务状态转换](#调度任务状态转换) +8. [配置示例](#配置示例) +9. [调度性能优化与大规模任务管理](#调度性能优化与大规模任务管理) +10. [结论](#结论) + +## 引言 + +DataVines任务调度系统是数据质量监控和元数据管理的核心组件,基于Quartz框架实现。该系统负责调度数据质量检查、元数据抓取等周期性任务,确保数据治理流程的自动化和可靠性。本文档详细描述了DataVines的调度机制,包括任务元数据封装、执行逻辑、生命周期管理、高可用设计以及性能优化策略。 + +## 基于Quartz的任务调度机制 + +DataVines采用Quartz作为其任务调度引擎,通过`QuartzExecutors`类封装了Quartz的核心功能。该类作为单例存在,负责与Quartz的`Scheduler`实例交互,管理所有调度任务的增删改查。 + +调度机制的核心流程如下: +1. **任务创建**:当用户创建一个调度任务时,系统会生成一个`ScheduleJobInfo`对象,该对象包含了任务的所有元数据。 +2. **任务添加**:`QuartzExecutors`接收`ScheduleJobInfo`和任务执行类(如`DataQualityScheduleJob.class`),将其注册到Quartz调度器中。 +3. **触发器配置**:系统根据`ScheduleJobInfo`中的cron表达式创建`CronTrigger`,并配置任务的开始时间和结束时间。 +4. **任务执行**:Quartz调度器在预定时间触发任务,调用`DataQualityScheduleJob`的`execute`方法。 + +在添加任务时,系统会检查任务是否已存在。如果存在,则更新其触发器;如果不存在,则创建新的任务和触发器。这种设计确保了任务配置的幂等性。 + +```mermaid +sequenceDiagram +participant 用户 +participant JobScheduleServiceImpl +participant QuartzExecutors +participant QuartzScheduler +用户->>JobScheduleServiceImpl : 创建/更新调度任务 +JobScheduleServiceImpl->>JobScheduleServiceImpl : 验证任务是否存在 +JobScheduleServiceImpl->>JobScheduleServiceImpl : 构建ScheduleJobInfo +JobScheduleServiceImpl->>QuartzExecutors : addJob(DataQualityScheduleJob.class, scheduleJobInfo) +QuartzExecutors->>QuartzExecutors : 获取JobKey和TriggerKey +QuartzExecutors->>QuartzScheduler : checkExists(jobKey) +alt 任务已存在 +QuartzScheduler-->>QuartzExecutors : 返回true +QuartzExecutors->>QuartzScheduler : rescheduleJob(triggerKey, cronTrigger) +else 任务不存在 +QuartzScheduler-->>QuartzExecutors : 返回false +QuartzExecutors->>QuartzScheduler : addJob(jobDetail, false, true) +QuartzExecutors->>QuartzScheduler : scheduleJob(cronTrigger) +end +QuartzScheduler-->>QuartzExecutors : 操作结果 +QuartzExecutors-->>JobScheduleServiceImpl : 操作结果 +JobScheduleServiceImpl-->>用户 : 操作结果 +``` + +**图示来源** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java#L117-L123) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L74-L148) + +## ScheduleJobInfo元数据封装 + +`ScheduleJobInfo`类是调度任务的元数据载体,它封装了任务执行所需的所有信息。该类位于`io.datavines.server.dqc.coordinator.quartz`包中,使用Lombok的`@Data`注解自动生成getter、setter和toString方法。 + +`ScheduleJobInfo`的主要属性包括: +- **type** (`ScheduleJobType`):任务类型,如`DATA_QUALITY`(数据质量)或`CATALOG`(元数据)。 +- **taskType** (`CommonTaskType`):通用任务类型,如`DATA_QUALITY_REPORT`(数据质量报告)。 +- **datasourceId** (`Long`):数据源ID,用于标识任务关联的数据源。 +- **id** (`Long`):任务ID,唯一标识一个调度任务。 +- **cronExpression** (`String`):cron表达式,定义任务的执行计划。 +- **startTime** (`LocalDateTime`):任务的开始时间。 +- **endTime** (`LocalDateTime`):任务的结束时间。 + +这些元数据在任务执行时被序列化并存储在`JobDataMap`中,供`DataQualityScheduleJob`在执行时读取。例如,`jobId`和`datasourceId`被直接放入`JobDataMap`,而整个`ScheduleJobInfo`对象也被序列化后存储,以便在需要时进行反序列化。 + +```mermaid +classDiagram +class ScheduleJobInfo { ++ScheduleJobType type ++CommonTaskType taskType ++Long datasourceId ++Long id ++String cronExpression ++LocalDateTime startTime ++LocalDateTime endTime ++ScheduleJobInfo(ScheduleJobType, CommonTaskType, Long, Long, String, LocalDateTime, LocalDateTime) +} +class ScheduleJobType { ++DATA_QUALITY(0, "data_quality") ++CATALOG(1, "catalog") ++of(String) ScheduleJobType ++getCode() int ++getDescription() String +} +class CommonTaskType { ++CATALOG_METADATA_FETCH(0, "catalog_metadata_fetch", "元数据抓取") ++DATA_QUALITY_REPORT(1, "data_quality_report", "数据质量报告") ++of(Integer) CommonTaskType ++getCode() int ++getDescription() String ++getZhDescription() String +} +ScheduleJobInfo --> ScheduleJobType : "包含" +ScheduleJobInfo --> CommonTaskType : "包含" +``` + +**图示来源** +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java#L26-L57) +- [ScheduleJobType.java](file://datavines-server\src\main\java\io\datavines\server\enums\ScheduleJobType.java#L24-L64) +- [CommonTaskType.java](file://datavines-server\src\main\java\io\datavines\server\enums\CommonTaskType.java#L24-L74) + +## DataQualityScheduleJob执行逻辑 + +`DataQualityScheduleJob`是Quartz调度器执行的具体任务类,实现了`org.quartz.Job`接口。当调度器触发任务时,会调用其`execute`方法。 + +执行逻辑的核心步骤如下: +1. **获取JobDataMap**:从`JobExecutionContext`中获取`JobDataMap`,该映射包含了在任务创建时存储的所有元数据。 +2. **提取任务ID**:从`JobDataMap`中读取`JOB_ID`,这是执行具体业务逻辑的关键。 +3. **获取执行时间**:从`JobExecutionContext`中获取`scheduledFireTime`(计划触发时间)和`fireTime`(实际触发时间),用于日志记录和业务处理。 +4. **获取业务服务**:通过`SpringApplicationContext`获取`JobExternalService`,这是与业务逻辑交互的入口。 +5. **执行任务**:调用`JobExternalService`的`execute`方法,传入`jobId`和`scheduleTime`,启动数据质量检查流程。 + +该类的设计遵循了依赖注入的原则,通过静态方法`SpringApplicationContext.getBean()`获取Spring容器中的Bean,避免了直接依赖Spring框架的`ApplicationContext`。 + +```mermaid +sequenceDiagram +participant QuartzScheduler +participant DataQualityScheduleJob +participant SpringApplicationContext +participant JobExternalService +participant JobService +QuartzScheduler->>DataQualityScheduleJob : execute(context) +DataQualityScheduleJob->>DataQualityScheduleJob : 获取JobDataMap +DataQualityScheduleJob->>DataQualityScheduleJob : 从JobDataMap提取jobId +DataQualityScheduleJob->>DataQualityScheduleJob : 获取scheduledFireTime和fireTime +DataQualityScheduleJob->>SpringApplicationContext : getBean(JobExternalService.class) +SpringApplicationContext-->>DataQualityScheduleJob : JobExternalService实例 +DataQualityScheduleJob->>JobExternalService : getJobById(jobId) +JobExternalService-->>DataQualityScheduleJob : Job实例 +alt Job不为空 +DataQualityScheduleJob->>JobExternalService : getJobService() +JobExternalService-->>DataQualityScheduleJob : JobService实例 +DataQualityScheduleJob->>JobService : execute(jobId, scheduleTime) +else Job为空 +DataQualityScheduleJob->>DataQualityScheduleJob : 记录警告日志 +end +``` + +**图示来源** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L54-L73) +- [JobExternalService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExternalService.java) + +## JobScheduler任务生命周期管理 + +任务的生命周期管理主要由`JobScheduleServiceImpl`和`QuartzExecutors`协同完成,涵盖了创建、启动、暂停和删除等操作。 + +### 创建与更新 +当用户创建或更新一个调度任务时,`JobScheduleServiceImpl`的`createOrUpdate`方法被调用。该方法首先检查任务是否已存在,然后调用`addScheduleJob`方法。在`addScheduleJob`中,根据任务类型(`CYCLE`或`CRONTAB`)构建`ScheduleJobInfo`,并调用`QuartzExecutors.addJob`方法将其注册到Quartz调度器。 + +### 删除 +删除操作通过`QuartzExecutors.deleteJob`方法实现。该方法接收一个`ScheduleJobInfo`对象,根据其`id`和`type`构建`JobKey`,然后调用Quartz调度器的`deleteJob`方法。如果任务不存在,方法返回`true`,体现了操作的幂等性。 + +### 暂停与恢复 +虽然代码中没有直接的“暂停”方法,但可以通过将任务的`status`设置为`false`(在`JobSchedule`实体中)来实现逻辑上的暂停。当`status`为`false`时,`JobScheduleServiceImpl`在创建或更新任务时不会调用`addJob`方法。恢复则通过将`status`重新设置为`true`来实现。 + +```mermaid +stateDiagram-v2 +[*] --> 未创建 +未创建 --> 已创建 : 创建任务 +已创建 --> 运行中 : 启动调度 +运行中 --> 暂停 : 暂停任务 +暂停 --> 运行中 : 恢复任务 +运行中 --> 已删除 : 删除任务 +暂停 --> 已删除 : 删除任务 +已创建 --> 已删除 : 删除任务 +``` + +**图示来源** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java#L65-L140) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L157-L173) + +## 高可用设计与故障转移机制 + +DataVines通过注册中心(Registry)和故障转移(Failover)机制实现高可用性。系统支持多种注册中心实现,如ZooKeeper和MySQL。 + +### 故障转移机制 +`CommonTaskFailover`类负责处理元数据抓取等通用任务的故障转移。当一个服务器实例宕机时,其他活跃的服务器实例会检测到这一变化,并接管其未完成的任务。 + +故障转移的触发时机包括: +1. **服务器下线**:当一个服务器从注册中心移除时,`Register`类会收到`REMOVE`事件,触发`handleJobExecutionFailover`和`handleMetaDataFetchTaskFailover`。 +2. **服务器启动**:当新的服务器实例启动时,它会查询注册中心,检查是否有需要故障转移的任务。 + +故障转移的执行流程如下: +1. 查询数据库,找出所有分配给已下线服务器但状态为“运行中”的任务。 +2. 更新这些任务的`executeHost`字段,将其指向当前服务器。 +3. 将这些任务重新放入任务队列,由当前服务器继续执行。 + +### 注册中心集成 +`Register`类是注册中心的抽象,它监听服务器列表的变化。当服务器列表发生变化时,它会执行故障转移逻辑,确保任务不会因为单点故障而丢失。 + +```mermaid +sequenceDiagram +participant ServerA +participant ServerB +participant Registry +participant Database +ServerA->>Registry : 注册 +ServerB->>Registry : 注册 +loop 心跳 +ServerA->>Registry : 发送心跳 +ServerB->>Registry : 发送心跳 +end +Note over ServerA : ServerA宕机 +Registry->>Registry : 检测到ServerA心跳超时 +Registry->>Registry : 触发REMOVE事件 +Registry->>CommonTaskFailover : handleMetaDataFetchTaskFailover(ServerA地址) +CommonTaskFailover->>Database : 查询ServerA上未完成的任务 +Database-->>CommonTaskFailover : 任务列表 +CommonTaskFailover->>CommonTaskFailover : 更新任务的executeHost为ServerB +CommonTaskFailover->>Database : 批量更新任务 +CommonTaskFailover->>CommonTaskManager : 将任务重新放入队列 +``` + +**图示来源** +- [CommonTaskFailover.java](file://datavines-server\src\main\java\io\datavines\server\scheduler\CommonTaskFailover.java#L30-L67) +- [Register.java](file://datavines-server\src\main\java\io\datavines\server\registry\Register.java#L93-L169) + +## 调度任务状态转换 + +调度任务的状态主要由`JobSchedule`实体的`status`字段表示,这是一个布尔值,`true`表示启用(在线),`false`表示禁用(离线)。 + +状态转换图如下: +- **创建**:新创建的任务默认为`true`(启用)。 +- **启用/禁用**:用户可以通过界面或API切换任务的`status`。 +- **删除**:任务被删除后,其状态不再存在。 + +```mermaid +stateDiagram-v2 +[*] --> 离线 +离线 --> 在线 : 启用 +在线 --> 离线 : 禁用 +在线 --> 已删除 : 删除 +离线 --> 已删除 : 删除 +``` + +**图示来源** +- [JobScheduleType.java](file://datavines-server\src\main\java\io\datavines\server\enums\JobScheduleType.java#L27-L28) + +## 配置示例 + +### Cron表达式配置 +在前端UI中,用户可以选择不同的调度周期(如每小时、每天、每周),系统会根据选择生成相应的cron表达式。例如: +- **每小时**:`0 0 * * * ?` (每小时的第0分钟) +- **每天**:`0 0 2 * * ?` (每天凌晨2点) +- **每周**:`0 0 2 ? * MON` (每周一凌晨2点) + +### API请求示例 +创建一个数据质量调度任务的API请求体示例: +```json +{ + "jobId": 123, + "type": "crontab", + "cronExpression": "0 0 2 * * ?", + "startTime": "2023-01-01T00:00:00", + "endTime": "2024-01-01T00:00:00", + "status": true +} +``` + +**图示来源** +- [index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\components\Schedule\index.tsx#L356-L366) + +## 调度性能优化与大规模任务管理 + +### 性能优化 +1. **线程池管理**:系统使用`ThreadUtils`工具类创建守护线程池,避免线程泄漏。例如,`newDaemonFixedThreadPool`方法创建固定大小的线程池,并为线程命名,便于监控和调试。 +2. **锁机制**:`QuartzExecutors`使用`ReentrantReadWriteLock`来保证在添加和删除任务时的线程安全,写操作使用写锁,确保操作的原子性。 +3. **Cron表达式验证**:在添加任务前,系统会调用`QuartzExecutors.isValid`方法验证cron表达式的有效性,避免无效表达式导致调度器异常。 + +### 大规模任务管理 +1. **分片处理**:`CommonTaskScheduler`类在运行时会检查系统资源(CPU负载、内存),如果资源不足,则会休眠一段时间,避免因任务过多导致服务器过载。 +2. **批量操作**:`QuartzExecutors`提供了`deleteAllJobs`方法,可以一次性删除某个任务组下的所有任务,提高管理效率。 +3. **未来执行计划计算**:`QuartzExecutors.listFutureCronRunTimes`方法可以计算cron表达式的未来执行时间,帮助用户预览调度计划。 + +```mermaid +flowchart TD +A[开始] --> B{资源检查} +B --> |资源充足| C[处理任务队列] +B --> |资源不足| D[休眠SLEEP_TIME_MILLIS] +D --> B +C --> E{有任务?} +E --> |是| F[执行任务] +F --> G[更新任务状态] +G --> E +E --> |否| H[休眠] +H --> B +``` + +**图示来源** +- [ThreadUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\ThreadUtils.java#L97-L136) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L239-L263) +- [CommonTaskScheduler.java](file://datavines-server\src\main\java\io\datavines\server\scheduler\CommonTaskScheduler.java#L55-L57) + +## 结论 + +DataVines的任务调度系统是一个功能完备、高可用的解决方案。它基于成熟的Quartz框架,通过`ScheduleJobInfo`封装任务元数据,由`DataQualityScheduleJob`执行具体业务逻辑。`JobScheduler`通过`QuartzExecutors`和`JobScheduleServiceImpl`实现了任务的全生命周期管理。系统的高可用性通过注册中心和`CommonTaskFailover`机制得到保障。此外,通过合理的线程池管理、锁机制和资源检查,系统能够高效地处理大规模任务调度需求。整体设计清晰,扩展性强,为数据质量监控和元数据管理提供了可靠的自动化基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\344\273\273\345\212\241\350\260\203\345\272\246/\346\211\247\350\241\214\351\200\273\350\276\221.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\344\273\273\345\212\241\350\260\203\345\272\246/\346\211\247\350\241\214\351\200\273\350\276\221.md" new file mode 100644 index 00000000..ea329d18 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\344\273\273\345\212\241\350\260\203\345\272\246/\346\211\247\350\241\214\351\200\273\350\276\221.md" @@ -0,0 +1,204 @@ +# 执行逻辑 + + +**本文档引用的文件** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [JobExecutionResponseProcessor.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseProcessor.java) +- [JobExecuteBootstrap.java](file://datavines-runner\src\main\java\io\datavines\runner\JobExecuteBootstrap.java) +- [CommandContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\CommandContext.java) +- [JobExecutionResponseContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseContext.java) +- [JobExecuteResponseCommand.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\JobExecuteResponseCommand.java) +- [TimeoutStrategy.java](file://datavines-common\src\main\java\io\datavines\common\enums\TimeoutStrategy.java) +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java) + + +## 目录 +1. [任务触发与调度](#任务触发与调度) +2. [上下文初始化](#上下文初始化) +3. [任务执行命令生成与发送](#任务执行命令生成与发送) +4. [执行结果处理](#执行结果处理) +5. [异常处理机制](#异常处理机制) +6. [任务执行时序图](#任务执行时序图) + +## 任务触发与调度 + +DataVines任务执行流程始于`DataQualityScheduleJob`类,该类实现了Quartz调度框架的Job接口,负责处理数据质量任务的调度执行。当调度器触发与任务关联的触发器时,会调用`execute`方法。 + +在`execute`方法中,首先从`JobExecutionContext`中获取任务ID和调度时间,然后通过`JobExternalService`获取具体的任务信息。如果任务存在,则调用`getJobService().execute()`方法启动任务执行流程。该流程是整个任务执行生命周期的起点,负责将调度事件转化为具体的执行请求。 + +```mermaid +sequenceDiagram +participant Scheduler as 调度器 +participant DataQualityScheduleJob as DataQualityScheduleJob +participant JobExternalService as JobExternalService +participant JobService as JobService +Scheduler->>DataQualityScheduleJob : 触发execute() +DataQualityScheduleJob->>DataQualityScheduleJob : 获取JobDataMap +DataQualityScheduleJob->>DataQualityScheduleJob : 提取jobId +DataQualityScheduleJob->>JobExternalService : getJobById(jobId) +JobExternalService-->>DataQualityScheduleJob : 返回Job对象 +DataQualityScheduleJob->>JobService : execute(jobId, scheduleTime) +``` + +**Diagram sources** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L54-L72) + +**Section sources** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L37-L72) + +## 上下文初始化 + +任务执行的上下文初始化过程主要在`JobExecuteManager`中完成。当任务被调度执行时,`JobExecuteManager`负责构建`JobExecutionRequest`对象,该对象包含了任务执行所需的所有配置和参数。 + +初始化过程包括: +1. 从数据库获取任务执行信息 +2. 解析任务参数,构建`JobExecutionParameter` +3. 加载执行平台和引擎配置 +4. 设置错误数据存储和验证结果存储配置 +5. 构建完整的执行请求上下文 + +这个过程确保了任务执行所需的所有环境和配置信息都已准备就绪,为后续的命令生成和发送奠定了基础。 + +**Section sources** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L555-L571) + +## 任务执行命令生成与发送 + +任务执行命令的生成和发送由`JobExecuteManager`类中的`JobExecutionExecutor`线程负责。该线程从`jobExecutionQueue`中获取`CommandContext`对象,并根据命令类型执行相应的操作。 + +当接收到`JOB_EXECUTE_REQUEST`命令时,系统会调用`executeJobExecution`方法来执行任务,并为该任务创建一个超时定时器`JobExecutionTimeoutTimerTask`。这个定时器会在指定时间后触发,如果任务仍未完成,则会执行超时处理逻辑。 + +命令的发送是通过将`CommandContext`对象放入`jobExecutionQueue`队列来实现的,这是一种典型的生产者-消费者模式,确保了任务执行请求的有序处理。 + +```mermaid +sequenceDiagram +participant JobExecuteManager as JobExecuteManager +participant JobExecutionExecutor as JobExecutionExecutor +participant JobExecutionRequest as JobExecutionRequest +participant WheelTimer as WheelTimer +JobExecuteManager->>JobExecuteManager : addExecuteCommand() +JobExecuteManager->>JobExecuteManager : 创建CommandContext +JobExecuteManager->>JobExecuteManager : 设置JOB_EXECUTE_REQUEST +JobExecuteManager->>JobExecuteManager : 放入jobExecutionQueue +JobExecutionExecutor->>JobExecutionExecutor : 从队列获取CommandContext +JobExecutionExecutor->>JobExecuteManager : executeJobExecution() +JobExecuteManager->>WheelTimer : newTimeout() +WheelTimer->>WheelTimer : 创建JobExecutionTimeoutTimerTask +``` + +**Diagram sources** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L142-L160) +- [CommandContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\CommandContext.java#L24-L30) + +**Section sources** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L142-L160) + +## 执行结果处理 + +执行结果的处理由`JobExecutionResponseProcessor`和`JobExecuteManager`协同完成。`JobExecutionResponseProcessor`是一个单例类,负责接收来自执行器的响应命令,并将其转发给`JobExecuteManager`进行处理。 + +`JobExecuteManager`内部有一个`JobExecutionResponseOperator`线程,它持续从`responseQueue`中获取`JobExecutionResponseContext`对象,并根据响应类型更新任务状态。对于`JOB_EXECUTE_ACK`响应,系统会更新任务的开始时间、执行主机和日志路径等信息;对于`JOB_EXECUTE_RESPONSE`响应,系统会更新任务的结束时间、状态和应用ID等信息。 + +这种异步响应处理机制确保了任务执行结果能够被及时处理,同时不会阻塞主执行流程。 + +```mermaid +sequenceDiagram +participant JobExecutionResponseProcessor as JobExecutionResponseProcessor +participant JobExecuteManager as JobExecuteManager +participant JobExecutionResponseOperator as JobExecutionResponseOperator +participant JobExternalService as JobExternalService +JobExecutionResponseProcessor->>JobExecuteManager : processJobExecutionExecuteResponse() +JobExecuteManager->>JobExecuteManager : 创建JobExecutionResponseContext +JobExecuteManager->>JobExecuteManager : 放入responseQueue +JobExecutionResponseOperator->>JobExecutionResponseOperator : 从队列获取响应 +JobExecutionResponseOperator->>JobExternalService : getJobExecutionById() +JobExecutionResponseOperator->>JobExternalService : updateJobExecution() +``` + +**Diagram sources** +- [JobExecutionResponseProcessor.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseProcessor.java#L39-L41) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L276-L304) +- [JobExecutionResponseContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseContext.java#L26-L38) + +**Section sources** +- [JobExecutionResponseProcessor.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseProcessor.java#L21-L43) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L276-L304) + +## 异常处理机制 + +DataVines的异常处理机制包含重试策略、超时处理和错误日志记录三个主要方面。 + +### 重试策略 +当任务执行失败时,系统会根据任务配置的重试次数进行重试。如果`jobExecution.getRetryTimes() > 0`,则会创建一个新的`CommandContext`并重新放入执行队列,同时更新数据库中的重试次数。如果重试次数已用完,则会发送错误邮件并更新任务状态。 + +### 超时处理 +系统使用`WheelTimer`来管理任务超时。每个任务执行请求都会关联一个`JobExecutionTimeoutTimerTask`,当任务执行时间超过预设阈值时,定时器会触发`doKillCommand`方法,该方法会调用`JobRunner.kill()`来终止任务执行,并将任务状态更新为`KILL`。 + +### 错误日志记录 +系统通过`LoggerUtils`和`JobExecutionLogFilter`等组件来记录详细的错误日志。所有关键操作和异常都会被记录到日志文件中,便于后续的故障排查和审计。 + +```mermaid +flowchart TD +A[任务执行失败] --> B{重试次数 > 0?} +B --> |是| C[创建新的CommandContext] +C --> D[放入执行队列] +D --> E[更新重试次数] +B --> |否| F[发送错误邮件] +F --> G[更新任务状态为FAILURE] +H[任务执行超时] --> I[触发JobExecutionTimeoutTimerTask] +I --> J[调用doKillCommand] +J --> K[终止任务执行] +K --> L[更新任务状态为KILL] +``` + +**Diagram sources** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L321-L334) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L404-L445) +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java#L78-L141) + +**Section sources** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L321-L334) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L404-L445) + +## 任务执行时序图 + +以下是DataVines任务执行的完整时序图,展示了从任务调度到结果处理的整个流程: + +```mermaid +sequenceDiagram +participant Scheduler as 调度器 +participant DataQualityScheduleJob as DataQualityScheduleJob +participant JobExternalService as JobExternalService +participant JobService as JobService +participant JobExecuteManager as JobExecuteManager +participant JobExecutionExecutor as JobExecutionExecutor +participant JobRunner as JobRunner +participant JobExecuteBootstrap as JobExecuteBootstrap +participant JobExecutionResponseProcessor as JobExecutionResponseProcessor +participant JobExecutionResponseOperator as JobExecutionResponseOperator +Scheduler->>DataQualityScheduleJob : 触发execute() +DataQualityScheduleJob->>JobExternalService : getJobById() +JobExternalService-->>DataQualityScheduleJob : 返回Job +DataQualityScheduleJob->>JobService : execute() +JobService->>JobExecuteManager : addExecuteCommand() +JobExecuteManager->>JobExecuteManager : 创建CommandContext +JobExecuteManager->>JobExecuteManager : 放入jobExecutionQueue +JobExecutionExecutor->>JobExecuteManager : executeJobExecution() +JobExecuteManager->>JobRunner : 启动JobRunner +JobRunner->>JobExecuteBootstrap : 执行main方法 +JobExecuteBootstrap->>JobExecuteBootstrap : 读取参数文件 +JobExecuteBootstrap->>JobExecuteBootstrap : 构建JobExecutionInfo +JobExecuteBootstrap->>JobExecuteBootstrap : 生成配置 +JobExecuteBootstrap->>JobExecuteBootstrap : 发送执行请求 +JobRunner-->>JobExecutionResponseProcessor : 返回执行结果 +JobExecutionResponseProcessor->>JobExecuteManager : 处理响应 +JobExecuteManager->>JobExecuteManager : 创建JobExecutionResponseContext +JobExecuteManager->>JobExecuteManager : 放入responseQueue +JobExecutionResponseOperator->>JobExternalService : 更新任务状态 +``` + +**Diagram sources** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L54-L72) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L142-L160) +- [JobExecuteBootstrap.java](file://datavines-runner\src\main\java\io\datavines\runner\JobExecuteBootstrap.java#L35-L62) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\344\273\273\345\212\241\350\260\203\345\272\246/\350\260\203\345\272\246\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\344\273\273\345\212\241\350\260\203\345\272\246/\350\260\203\345\272\246\347\256\241\347\220\206.md" new file mode 100644 index 00000000..cd030dab --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\344\273\273\345\212\241\350\260\203\345\272\246/\350\260\203\345\272\246\347\256\241\347\220\206.md" @@ -0,0 +1,375 @@ +# 调度管理 + + +**本文档引用文件** +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [JobSchedule.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobSchedule.java) +- [JobScheduleController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\JobScheduleController.java) +- [JobScheduleType.java](file://datavines-server\src\main\java\io\datavines\server\enums\JobScheduleType.java) +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java) +- [ThreadUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\ThreadUtils.java) + + +## 目录 +1. [调度元数据管理](#调度元数据管理) +2. [ScheduleJobInfo类解析](#schedulejobinfo类解析) +3. [JobScheduler与Quartz集成](#jobscheduler与quartz集成) +4. [调度任务状态机模型](#调度任务状态机模型) +5. [调度任务配置示例](#调度任务配置示例) +6. [API调用方式](#api调用方式) +7. [线程池与并发控制](#线程池与并发控制) + +## 调度元数据管理 + +DataVines调度系统通过JobSchedule实体类管理调度任务的元数据信息。该实体类存储了调度任务的核心配置,包括任务ID、调度类型、参数配置、Cron表达式、状态以及时间范围等信息。调度元数据通过数据库表`dv_job_schedule`进行持久化存储,确保调度配置的可靠性和可追溯性。 + +**调度元数据属性说明:** +- **jobId**: 关联的作业ID,标识被调度的具体任务 +- **type**: 调度类型,支持周期调度(CYCLE)、Cron调度(CRONTAB)和离线调度(OFFLINE) +- **param**: 调度参数,以JSON格式存储具体的调度配置 +- **cronExpression**: Cron表达式,定义任务的执行时间规则 +- **status**: 调度状态,true表示启用,false表示禁用 +- **startTime/endTime**: 调度任务的有效时间范围 + +**调度元数据生命周期:** +调度任务的元数据遵循创建、更新、删除的完整生命周期。当用户创建或更新调度配置时,系统首先验证参数的合法性,然后生成相应的Cron表达式并持久化到数据库。在调度任务执行过程中,元数据信息被加载到内存中供调度器使用。 + +```mermaid +flowchart TD +A[创建调度任务] --> B[验证参数] +B --> C{调度类型} +C --> |周期调度| D[生成周期Cron表达式] +C --> |Cron调度| E[验证Cron表达式] +C --> |离线调度| F[设置状态为禁用] +D --> G[持久化到数据库] +E --> G +F --> G +G --> H[注册到Quartz调度器] +``` + +**调度元数据管理** +- [JobSchedule.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobSchedule.java#L35-L74) +- [JobScheduleType.java](file://datavines-server\src\main\java\io\datavines\server\enums\JobScheduleType.java#L28-L30) + +## ScheduleJobInfo类解析 + +ScheduleJobInfo类是调度任务配置信息的核心封装类,负责将调度任务的各种属性整合为一个统一的数据结构,供调度器使用。该类作为Quartz调度框架与业务逻辑之间的桥梁,确保调度信息的正确传递。 + +```mermaid +classDiagram +class ScheduleJobInfo { ++ScheduleJobType type ++CommonTaskType taskType ++Long datasourceId ++Long id ++String cronExpression ++LocalDateTime startTime ++LocalDateTime endTime ++ScheduleJobInfo(ScheduleJobType, CommonTaskType, Long, Long, String, LocalDateTime, LocalDateTime) +} +ScheduleJobType <|-- ScheduleJobInfo : "包含" +CommonTaskType <|-- ScheduleJobInfo : "包含" +``` + +**类属性说明:** +- **type**: 调度任务类型,目前支持数据质量调度(DATA_QUALITY) +- **taskType**: 通用任务类型,用于区分不同类型的业务任务 +- **datasourceId**: 数据源ID,标识任务关联的数据源 +- **id**: 任务ID,唯一标识一个调度任务 +- **cronExpression**: Cron表达式,定义任务的执行计划 +- **startTime/endTime**: 任务调度的有效时间窗口 + +**构造函数与初始化:** +ScheduleJobInfo类提供了完整的构造函数,确保所有必要属性在实例化时被正确初始化。该类使用Lombok的@Data注解,自动生成getter、setter、equals、hashCode和toString方法,简化了代码维护。 + +**调度信息转换:** +在任务创建或更新时,系统会将JobSchedule实体转换为ScheduleJobInfo对象,这个过程包括: +1. 从JobSchedule中提取基础信息 +2. 根据调度类型生成或验证Cron表达式 +3. 设置任务关联的数据源信息 +4. 确定任务的有效时间范围 + +**ScheduleJobInfo类解析** +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java#L27-L57) + +## JobScheduler与Quartz集成 + +DataVines通过QuartzExecutors类实现与Quartz调度框架的集成,提供了任务的创建、启动、暂停、恢复和删除等核心操作。Quartz作为成熟的开源调度框架,为DataVines提供了可靠的定时任务执行能力。 + +```mermaid +sequenceDiagram +participant UI as 用户界面 +participant Controller as JobScheduleController +participant Service as JobScheduleServiceImpl +participant Quartz as QuartzExecutors +participant Scheduler as Quartz Scheduler +UI->>Controller : 创建/更新调度请求 +Controller->>Service : createOrUpdate() +Service->>Service : 验证参数并生成Cron +Service->>Quartz : addJob() +Quartz->>Scheduler : 创建JobDetail和Trigger +Scheduler-->>Quartz : 返回结果 +Quartz-->>Service : 操作结果 +Service-->>Controller : 返回调度信息 +Controller-->>UI : 返回响应 +``` + +**任务创建流程:** +1. **JobDetail创建**:根据任务类型创建JobDetail对象,包含任务执行类和相关数据 +2. **Trigger创建**:基于Cron表达式创建CronTrigger,定义任务的执行计划 +3. **调度注册**:将JobDetail和Trigger注册到Quartz调度器中 + +**核心操作方法:** +- **addJob()**: 添加或更新调度任务,如果任务已存在则更新其触发器 +- **deleteJob()**: 删除指定的调度任务 +- **deleteAllJobs()**: 删除指定作业组中的所有任务 + +**调度器特性:** +- 使用ReadWriteLock保证并发安全 +- 支持Cron表达式验证 +- 提供未来执行时间列表查询功能 +- 处理时区转换,确保时间准确性 + +**JobScheduler与Quartz集成** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L74-L263) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java#L117-L128) + +## 调度任务状态机模型 + +DataVines调度系统实现了完整的任务状态机模型,管理调度任务从创建到完成的整个生命周期。状态机模型确保了任务状态转换的正确性和一致性。 + +```mermaid +stateDiagram-v2 +[*] --> 待调度 +待调度 --> 运行中 : 任务触发 +运行中 --> 已暂停 : 用户暂停 +运行中 --> 已完成 : 任务成功 +运行中 --> 失败 : 任务执行失败 +已暂停 --> 运行中 : 用户恢复 +已暂停 --> 已完成 : 任务结束 +失败 --> 待重试 : 需要容错 +待重试 --> 运行中 : 重试执行 +已完成 --> [*] +失败 --> [*] +``` + +**核心状态定义:** +- **待调度(SUBMITTED_SUCCESS)**: 任务已提交,等待执行 +- **运行中(RUNNING_EXECUTION)**: 任务正在执行 +- **准备暂停(READY_PAUSE)**: 任务收到暂停请求,等待当前操作完成 +- **已暂停(PAUSE)**: 任务已暂停,可恢复执行 +- **准备停止(READY_STOP)**: 任务收到停止请求,等待清理资源 +- **已停止(STOP)**: 任务已停止,不可恢复 +- **失败(FAILURE)**: 任务执行失败 +- **成功(SUCCESS)**: 任务执行成功 + +**状态转换规则:** +1. 任务只能从"待调度"状态进入"运行中"状态 +2. "运行中"状态可转换为"已暂停"、"失败"或"成功"状态 +3. "已暂停"状态可恢复为"运行中"状态 +4. 一旦进入"已停止"状态,任务不可恢复 + +**状态管理方法:** +- **typeIsSuccess()**: 判断状态是否为成功 +- **typeIsFailure()**: 判断状态是否为失败 +- **typeIsFinished()**: 判断状态是否为结束状态 +- **typeIsRunning()**: 判断状态是否为运行中 +- **canPause()**: 判断任务是否可以暂停 + +**调度任务状态机模型** +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java#L45-L56) + +## 调度任务配置示例 + +### JSON配置示例 + +**周期调度配置:** +```json +{ + "jobId": 123, + "type": "cycle", + "param": { + "cycle": "daily", + "hour": 2, + "minute": 30 + }, + "startTime": "2024-01-01T00:00:00", + "endTime": "2024-12-31T23:59:59", + "status": true +} +``` + +**Cron调度配置:** +```json +{ + "jobId": 123, + "type": "cron", + "param": { + "crontab": "0 30 2 * * ?" + }, + "startTime": "2024-01-01T00:00:00", + "endTime": "2024-12-31T23:59:59", + "status": true +} +``` + +**离线调度配置:** +```json +{ + "jobId": 123, + "type": "offline", + "status": false +} +``` + +### 配置参数说明 + +| 参数 | 说明 | 示例值 | +|------|------|--------| +| jobId | 任务ID | 123 | +| type | 调度类型 | cycle/cron/offline | +| param | 调度参数 | {"cycle": "daily", "hour": 2} | +| cronExpression | Cron表达式 | 0 30 2 * * ? | +| startTime | 开始时间 | 2024-01-01T00:00:00 | +| endTime | 结束时间 | 2024-12-31T23:59:59 | +| status | 调度状态 | true/false | + +**调度任务配置示例** +- [JobSchedule.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobSchedule.java#L35-L74) + +## API调用方式 + +DataVines提供了RESTful API接口,支持调度任务的创建、查询和管理操作。 + +### 创建或更新调度任务 + +**请求方式:** POST +**请求路径:** /api/v1/job/schedule/createOrUpdate +**请求头:** Content-Type: application/json +**请求体:** +```json +{ + "jobId": 123, + "type": "cycle", + "param": { + "cycle": "daily", + "hour": 2, + "minute": 30 + }, + "startTime": "2024-01-01T00:00:00", + "endTime": "2024-12-31T23:59:59" +} +``` + +**响应示例:** +```json +{ + "code": 0, + "message": "success", + "data": { + "id": 456, + "jobId": 123, + "type": "cycle", + "cronExpression": "0 30 2 * * ?", + "status": true, + "createTime": "2024-01-01T10:00:00" + } +} +``` + +### 查询调度任务 + +**请求方式:** GET +**请求路径:** /api/v1/job/schedule/{jobId} +**响应示例:** +```json +{ + "code": 0, + "message": "success", + "data": { + "id": 456, + "jobId": 123, + "type": "cycle", + "param": "{\"cycle\":\"daily\",\"hour\":2,\"minute\":30}", + "cronExpression": "0 30 2 * * ?", + "status": true, + "startTime": "2024-01-01T00:00:00", + "endTime": "2024-12-31T23:59:59" + } +} +``` + +### 获取Cron表达式 + +**请求方式:** POST +**请求路径:** /api/v1/job/schedule/cron +**请求体:** +```json +{ + "cycle": "daily", + "hour": 2, + "minute": 30 +} +``` + +**API调用方式** +- [JobScheduleController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\JobScheduleController.java#L48-L68) + +## 线程池与并发控制 + +DataVines通过ThreadUtils工具类和Quartz调度框架的线程池配置,实现了高效的并发控制策略。 + +### 线程池配置 + +**核心线程池工具方法:** +- **newDaemonCachedThreadPool()**: 创建守护线程缓存池 +- **newThreadScheduledExecutor()**: 创建定时任务执行器 +- **newFixedThreadPool()**: 创建固定大小线程池 + +```mermaid +flowchart TD +A[任务提交] --> B{任务类型} +B --> |普通任务| C[缓存线程池] +B --> |定时任务| D[定时线程池] +B --> |IO密集型| E[固定大小线程池] +C --> F[动态创建线程] +D --> G[定时调度执行] +E --> H[固定线程数处理] +``` + +### 并发控制策略 + +**读写锁机制:** +QuartzExecutors使用ReentrantReadWriteLock确保调度操作的线程安全: +- 写操作(添加、删除任务)获取写锁 +- 读操作(查询任务状态)获取读锁 +- 多个读操作可并发执行 +- 写操作独占锁,阻止其他读写操作 + +**并发限制:** +系统通过以下方式控制并发: +1. **资源检查**:在任务调度前检查CPU和内存资源 +2. **执行阈值**:设置不同类型引擎的最大执行数 +3. **重试退避**:失败任务采用指数退避策略重试 + +**线程池配置示例:** +```java +public static ScheduledExecutorService newThreadScheduledExecutor( + String threadName, int corePoolSize, boolean isDaemon) { + ThreadFactory threadFactory = new ThreadFactoryBuilder() + .setDaemon(isDaemon) + .setNameFormat(threadName) + .build(); + ScheduledThreadPoolExecutor executor = + new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); + executor.setRemoveOnCancelPolicy(true); + return executor; +} +``` + +**线程池与并发控制** +- [ThreadUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\ThreadUtils.java#L145-L155) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L62) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/Livy\346\211\247\350\241\214.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/Livy\346\211\247\350\241\214.md" new file mode 100644 index 00000000..860fedd8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/Livy\346\211\247\350\241\214.md" @@ -0,0 +1,289 @@ +# Livy执行 + + +**本文档引用的文件** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\SparkParameters.java) +- [LivySparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\LivySparkParameters.java) + + +## 目录 +1. [简介](#简介) +2. [Livy执行引擎架构](#livy执行引擎架构) +3. [LivyEngineExecutor与Livy服务器交互机制](#livyengineexecutor与livy服务器交互机制) +4. [Spark作业提交流程](#spark作业提交流程) +5. [会话管理与资源回收策略](#会话管理与资源回收策略) +6. [网络通信与超时处理](#网络通信与超时处理) +7. [Livy集成最佳实践与性能调优](#livy集成最佳实践与性能调优) +8. [结论](#结论) + +## 简介 +DataVines Livy执行引擎是用于通过Livy服务器提交和管理Spark作业的核心组件。本文件详细描述了LivyEngineExecutor与Livy服务器的交互机制,解释了Spark作业通过Livy提交的完整流程,说明了会话管理和资源回收策略,分析了Livy模式下的网络通信和超时处理,并提供了Livy集成的最佳实践和性能调优建议。 + +## Livy执行引擎架构 +DataVines的Livy执行引擎基于分层架构设计,核心组件包括LivyEngineExecutor、LivyCommandProcess和LivyTaskSubmitHelper。LivyEngineExecutor继承自AbstractLivyEngineExecutor,实现了与Livy服务器的交互逻辑。LivyCommandProcess负责处理与Livy REST API的通信,而LivyTaskSubmitHelper则提供了作业提交的辅助功能。 + +```mermaid +classDiagram +class AbstractLivyEngineExecutor { ++submitJob(jobRequest) JobExecutionResult ++getJobStatus(jobId) String ++killJob(jobId) boolean ++getJobLog(jobId) String +} +class LivyEngineExecutor { ++submitJob(jobRequest) JobExecutionResult ++getJobStatus(jobId) String ++killJob(jobId) boolean ++getJobLog(jobId) String +-buildLivyRequest(jobRequest) Map +-processLivyResponse(response) JobExecutionResult +} +class LivyCommandProcess { ++submitLivyJob(request) HttpResponse ++getLivySessionStatus(sessionId) HttpResponse ++killLivySession(sessionId) HttpResponse ++getLivySessionLog(sessionId) HttpResponse +-sendHttpRequest(url, method, body) HttpResponse +-buildHttpHeaders() Map +} +class LivyTaskSubmitHelper { ++buildSparkSubmitRequest(jobRequest, sparkParams) Map ++validateSparkParameters(params) boolean ++generateSessionName(jobId) String +} +class LivyStates { ++STARTING ++RECOVERING ++IDLE ++BUSY ++SHUTTING_DOWN ++ERROR ++DEAD +} +AbstractLivyEngineExecutor <|-- LivyEngineExecutor +LivyEngineExecutor --> LivyCommandProcess : "使用" +LivyEngineExecutor --> LivyTaskSubmitHelper : "使用" +LivyEngineExecutor --> LivyStates : "引用" +``` + +**Diagram sources** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java) + +**Section sources** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) + +## LivyEngineExecutor与Livy服务器交互机制 +LivyEngineExecutor通过REST API与Livy服务器进行交互,实现了作业提交、状态查询、作业终止和日志获取等核心功能。交互过程遵循标准的HTTP协议,使用JSON格式进行数据交换。 + +```mermaid +sequenceDiagram +participant Client as "DataVines客户端" +participant Executor as "LivyEngineExecutor" +participant Command as "LivyCommandProcess" +participant LivyServer as "Livy服务器" +Client->>Executor : submitJob(jobRequest) +Executor->>LivyTaskSubmitHelper : buildSparkSubmitRequest() +LivyTaskSubmitHelper-->>Executor : 构建好的请求参数 +Executor->>Command : submitLivyJob(request) +Command->>Command : buildHttpHeaders() +Command->>Command : sendHttpRequest() +Command->>LivyServer : POST /sessions +LivyServer-->>Command : 201 Created + sessionId +Command-->>Executor : HttpResponse +Executor->>Executor : processLivyResponse() +Executor-->>Client : JobExecutionResult +Client->>Executor : getJobStatus(jobId) +Executor->>Command : getLivySessionStatus(sessionId) +Command->>LivyServer : GET /sessions/{sessionId} +LivyServer-->>Command : Session状态 +Command-->>Executor : HttpResponse +Executor-->>Client : 状态信息 +Client->>Executor : killJob(jobId) +Executor->>Command : killLivySession(sessionId) +Command->>LivyServer : DELETE /sessions/{sessionId} +LivyServer-->>Command : 204 No Content +Command-->>Executor : HttpResponse +Executor-->>Client : 终止结果 +Note over Client,LivyServer : 所有通信均通过HTTPS加密 +``` + +**Diagram sources** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) + +**Section sources** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) + +## Spark作业提交流程 +Spark作业通过Livy提交的完整流程包括参数准备、会话创建、代码执行和结果返回四个主要阶段。LivyEngineExecutor首先将作业请求转换为Livy API所需的格式,然后通过HTTP请求创建Spark会话,最后监控作业执行状态并获取结果。 + +```mermaid +flowchart TD +A["开始: submitJob()"] --> B["准备Spark参数"] +B --> C["构建Livy REST请求"] +C --> D["发送POST /sessions请求"] +D --> E{"响应状态"} +E --> |201 Created| F["获取会话ID"] +E --> |4xx/5xx| G["抛出异常"] +F --> H["轮询会话状态 GET /sessions/{id}"] +H --> I{"状态检查"} +I --> |IDLE/BUSY| J["继续轮询"] +I --> |SUCCESS| K["获取作业结果"] +I --> |ERROR/DEAD| L["获取错误日志"] +K --> M["返回成功结果"] +L --> N["返回错误信息"] +M --> O["结束"] +N --> O["结束"] +G --> O["结束"] +style A fill:#4CAF50,stroke:#388E3C +style O fill:#F44336,stroke:#D32F2F +``` + +**Diagram sources** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) + +**Section sources** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) + +## 会话管理与资源回收策略 +Livy执行引擎实现了完善的会话管理和资源回收策略,确保Spark会话的生命周期得到有效控制。会话状态由LivyStates枚举定义,包括STARTING、IDLE、BUSY、SHUTTING_DOWN、ERROR和DEAD等状态。 + +```mermaid +stateDiagram-v2 +[*] --> INIT +INIT --> CREATING : 创建会话 +CREATING --> STARTING : 201 Created +STARTING --> IDLE : 会话就绪 +STARTING --> ERROR : 创建失败 +IDLE --> BUSY : 提交代码 +BUSY --> IDLE : 代码执行完成 +BUSY --> ERROR : 执行异常 +IDLE --> SHUTTING_DOWN : 显式终止 +BUSY --> SHUTTING_DOWN : 显式终止 +SHUTTING_DOWN --> DEAD : 会话关闭 +ERROR --> SHUTTING_DOWN : 错误恢复 +ERROR --> DEAD : 无法恢复 +note right of CREATING +超时时间 : 60秒 +重试次数 : 3次 +end note +note right of IDLE +心跳间隔 : 30秒 +空闲超时 : 300秒 +end note +``` + +**Diagram sources** +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) + +**Section sources** +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java) + +## 网络通信与超时处理 +Livy模式下的网络通信采用HTTPS协议,确保数据传输的安全性。系统实现了多层次的超时处理机制,包括连接超时、读取超时和会话超时,以应对网络不稳定的情况。 + +```mermaid +flowchart LR +A["HTTP客户端配置"] --> B["连接超时: 30秒"] +A --> C["读取超时: 60秒"] +A --> D["连接请求超时: 10秒"] +A --> E["最大连接数: 100"] +A --> F["每个路由最大连接: 20"] +G["Livy会话配置"] --> H["会话创建超时: 60秒"] +G --> I["会话空闲超时: 300秒"] +G --> J["心跳间隔: 30秒"] +G --> K["最大重试次数: 3"] +L["错误处理策略"] --> M["指数退避重试"] +L --> N["熔断器模式"] +L --> O["连接池管理"] +B --> P["网络通信"] +C --> P +D --> P +H --> P +I --> P +J --> P +M --> P +N --> P +O --> P +``` + +**Diagram sources** +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) + +**Section sources** +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) + +## Livy集成最佳实践与性能调优 +为了确保Livy集成的稳定性和性能,建议遵循以下最佳实践和性能调优策略。这些策略涵盖了配置优化、资源管理和监控告警等方面。 + +```mermaid +erDiagram +CONFIGURATION ||--o{ PERFORMANCE : "影响" +CONFIGURATION ||--o{ STABILITY : "影响" +CONFIGURATION ||--o{ SECURITY : "影响" +CONFIGURATION { +string livy_url "Livy服务器地址" +string auth_type "认证类型" +string username "用户名" +string password "密码" +int connection_timeout "连接超时(秒)" +int socket_timeout "套接字超时(秒)" +int session_creation_timeout "会话创建超时(秒)" +int session_idle_timeout "会话空闲超时(秒)" +int heartbeat_interval "心跳间隔(秒)" +int max_retries "最大重试次数" +string retry_strategy "重试策略" +int circuit_breaker_threshold "熔断阈值" +int circuit_breaker_timeout "熔断超时(秒)" +} +PERFORMANCE { +string executor_memory "执行器内存" +string driver_memory "驱动器内存" +int num_executors "执行器数量" +int executor_cores "执行器核心数" +string queue "YARN队列" +string spark_conf "Spark配置" +} +STABILITY { +bool enable_ssl_verification "启用SSL验证" +bool enable_connection_pool "启用连接池" +bool enable_circuit_breaker "启用熔断器" +bool enable_retry_mechanism "启用重试机制" +string log_level "日志级别" +bool enable_metrics "启用指标收集" +} +SECURITY { +string ssl_certificate "SSL证书" +string ssl_key "SSL密钥" +bool enable_kerberos "启用Kerberos" +string kerberos_principal "Kerberos主体" +string kerberos_keytab "Kerberos密钥表" +} +``` + +**Diagram sources** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\SparkParameters.java) +- [LivySparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\LivySparkParameters.java) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) + +**Section sources** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\SparkParameters.java) +- [LivySparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\LivySparkParameters.java) + +## 结论 +DataVines Livy执行引擎通过LivyEngineExecutor组件实现了与Livy服务器的高效交互,提供了完整的Spark作业提交、监控和管理功能。系统采用分层架构设计,具有良好的可扩展性和可维护性。通过合理的会话管理、资源回收和超时处理机制,确保了在各种网络条件下的稳定运行。建议在实际部署中根据具体需求调整配置参数,并实施相应的监控和告警策略,以最大化系统性能和可靠性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/Yarn\346\211\247\350\241\214.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/Yarn\346\211\247\350\241\214.md" new file mode 100644 index 00000000..2a5bf74e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/Yarn\346\211\247\350\241\214.md" @@ -0,0 +1,570 @@ +# Yarn执行 + + +**本文档引用的文件** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java) + + +## 目录 +1. [Yarn执行引擎概述](#yarn执行引擎概述) +2. [AbstractYarnEngineExecutor抽象设计](#abstractyarnengineexecutor抽象设计) +3. [Yarn资源调度工作原理](#yarn资源调度工作原理) +4. [任务提交到Yarn集群的流程](#任务提交到yarn集群的流程) +5. [状态监控机制](#状态监控机制) +6. [容错和重试策略](#容错和重试策略) +7. [Yarn配置优化建议](#yarn配置优化建议) +8. [常见问题解决方案](#常见问题解决方案) + +## Yarn执行引擎概述 + +DataVines Yarn执行引擎是DataVines平台的核心组件之一,负责在Yarn集群上执行数据质量检查任务。该引擎通过抽象设计实现了对不同计算框架(如Flink、Spark)的统一调度和管理。Yarn执行引擎的主要功能包括任务提交、资源调度、状态监控、容错处理等。 + +Yarn执行引擎的设计遵循了分层架构原则,通过抽象基类和具体实现类的分离,实现了代码的可扩展性和可维护性。引擎的核心是`AbstractYarnEngineExecutor`抽象类,它定义了Yarn执行器的基本行为和接口。具体的执行器实现(如`FlinkEngineExecutor`和`SparkEngineExecutor`)继承自该抽象类,并根据具体计算框架的特点实现相应的功能。 + +**本文档引用的文件** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) + +## AbstractYarnEngineExecutor抽象设计 + +`AbstractYarnEngineExecutor`是DataVines Yarn执行引擎的核心抽象类,定义了所有Yarn执行器的公共行为和接口。该类继承自`AbstractEngineExecutor`,并提供了Yarn特定的功能实现。 + +```mermaid +classDiagram +class AbstractYarnEngineExecutor { ++shellCommandProcess ShellCommandProcess ++cancel() void +-killYarnApplication() void +} +class AbstractEngineExecutor { ++jobExecutionRequest JobExecutionRequest ++logger Logger ++cancel boolean ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest +} +class FlinkEngineExecutor { ++configurations Configurations ++processResult ProcessResult ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest ++buildCommand() String +} +class SparkEngineExecutor { ++configurations Configurations ++processResult ProcessResult ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest ++buildCommand() String +} +AbstractYarnEngineExecutor --> AbstractEngineExecutor : "extends" +FlinkEngineExecutor --> AbstractYarnEngineExecutor : "extends" +SparkEngineExecutor --> AbstractYarnEngineExecutor : "extends" +``` + +**图表来源** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L59) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L38-L87) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L87) + +### 核心字段和方法 + +`AbstractYarnEngineExecutor`类定义了以下核心字段和方法: + +- `shellCommandProcess`: `ShellCommandProcess`类型的字段,用于执行shell命令和管理进程 +- `cancel()`: 重写父类的取消方法,除了调用父类的取消逻辑外,还增加了Yarn应用的终止功能 +- `killYarnApplication()`: 私有方法,用于终止Yarn上的应用程序 + +`cancel()`方法的实现体现了Yarn执行器的特殊性。当任务被取消时,不仅要取消本地进程,还要通过Yarn命令终止远程的Yarn应用。这种方法确保了资源的及时释放,避免了资源泄漏。 + +### 继承关系和多态性 + +`AbstractYarnEngineExecutor`通过继承`AbstractEngineExecutor`类,实现了代码的复用和扩展。`AbstractEngineExecutor`定义了执行器的基本接口,而`AbstractYarnEngineExecutor`在此基础上增加了Yarn特定的功能。 + +具体的执行器实现(如`FlinkEngineExecutor`和`SparkEngineExecutor`)通过继承`AbstractYarnEngineExecutor`,获得了Yarn执行的基本能力。同时,它们可以根据具体计算框架的特点,实现特定的功能。这种设计模式体现了面向对象编程的多态性原则,使得系统具有良好的扩展性。 + +**本文档引用的文件** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) + +## Yarn资源调度工作原理 + +DataVines Yarn执行引擎的资源调度工作原理基于Yarn的资源管理机制。引擎通过YarnUtils工具类与Yarn集群进行交互,实现了资源的申请、监控和释放。 + +### Yarn模式配置 + +YarnUtils类定义了三种Yarn模式: + +- `none`: 不使用Yarn资源管理 +- `ha`: Yarn高可用模式 +- `standalone`: Yarn独立模式 + +```mermaid +stateDiagram-v2 +[*] --> 配置解析 +配置解析 --> Yarn模式判断 +Yarn模式判断 --> 不使用Yarn : yarn.mode=none +Yarn模式判断 --> 单节点模式 : yarn.mode=standalone +Yarn模式判断 --> 高可用模式 : yarn.mode=ha +不使用Yarn --> [*] +单节点模式 --> 获取应用URL +高可用模式 --> 获取活跃ResourceManager +获取活跃ResourceManager --> 获取应用URL +获取应用URL --> [*] +``` + +**图表来源** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L33-L76) + +### 资源调度流程 + +Yarn资源调度的主要流程如下: + +1. **配置解析**: 从配置中读取Yarn相关参数,包括模式、ResourceManager地址、端口等 +2. **模式判断**: 根据配置确定Yarn模式(none、standalone或ha) +3. **ResourceManager定位**: 在高可用模式下,通过HTTP请求确定活跃的ResourceManager +4. **应用URL构建**: 根据ResourceManager地址构建Yarn应用的状态查询URL +5. **资源申请**: 通过构建的命令提交任务到Yarn集群 + +在高可用模式下,系统会通过访问ResourceManager的集群信息接口来确定哪个节点处于ACTIVE状态。这个过程通过`getActiveResourceManagerName`方法实现,它会尝试访问配置中列出的所有ResourceManager节点,直到找到处于ACTIVE状态的节点。 + +### 应用状态查询 + +YarnUtils提供了`getApplicationUrl`方法来构建应用状态查询URL。该方法根据Yarn模式的不同,采用不同的URL构建策略: + +- 在standalone模式下,直接使用配置的地址 +- 在ha模式下,通过`getAppAddress`方法动态确定活跃ResourceManager的地址 +- 在none模式下,不启用Yarn功能 + +这种设计确保了系统在不同Yarn部署模式下的兼容性,使得DataVines可以在各种Yarn环境中正常运行。 + +**本文档引用的文件** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java) + +## 任务提交到Yarn集群的流程 + +DataVines任务提交到Yarn集群的流程是一个复杂的过程,涉及多个组件的协同工作。整个流程从任务初始化开始,到最终的命令执行结束。 + +### 任务提交序列图 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Executor as "执行器" +participant CommandProcess as "命令处理器" +participant Yarn as "Yarn集群" +Client->>Executor : init(初始化) +Executor->>Executor : 设置线程名称 +Executor->>Executor : 初始化字段 +Executor->>Executor : 创建ShellCommandProcess +Client->>Executor : execute(执行) +Executor->>Executor : 调用buildCommand() +Executor->>CommandProcess : run(命令) +CommandProcess->>CommandProcess : 构建命令文件 +CommandProcess->>CommandProcess : 启动进程 +CommandProcess->>Yarn : 提交Yarn任务 +Yarn-->>CommandProcess : 返回应用ID +CommandProcess->>CommandProcess : 监控进程状态 +CommandProcess->>CommandProcess : 解析输出 +CommandProcess-->>Executor : 返回执行结果 +Executor-->>Client : 完成 +``` + +**图表来源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L64-L72) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L81-L127) + +### 详细流程分析 + +任务提交流程可以分为以下几个阶段: + +#### 1. 初始化阶段 + +在`init`方法中,执行器完成以下初始化工作: +- 设置线程名称,便于日志追踪 +- 初始化必要的字段,如`jobExecutionRequest`、`logger`等 +- 创建`ShellCommandProcess`实例,用于后续的命令执行 + +#### 2. 命令构建阶段 + +`buildCommand`方法负责构建实际提交到Yarn的命令。以`SparkEngineExecutor`为例,该方法会: +- 解析任务参数 +- 设置主JAR包路径 +- 构建插件目录路径 +- 添加必要的JAR包依赖 +- 设置主类和参数 +- 添加Yarn标签用于后续的状态查询 + +#### 3. 命令执行阶段 + +`BaseCommandProcess`类的`run`方法负责执行构建好的命令: +- 创建命令文件 +- 构建`ProcessBuilder`并设置工作目录 +- 配置进程的用户权限(通过sudo) +- 启动进程并监控其状态 +- 收集和处理进程输出 + +#### 4. 状态确定阶段 + +任务执行完成后,需要确定最终状态: +- 如果不是Yarn任务,直接根据进程退出码判断 +- 如果是Yarn任务,通过`isSuccessOfYarnState`方法查询Yarn应用的最终状态 + +这种分阶段的设计使得任务提交流程清晰明了,每个阶段都有明确的职责,便于维护和扩展。 + +**本文档引用的文件** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java) + +## 状态监控机制 + +DataVines Yarn执行引擎的状态监控机制是确保任务可靠执行的关键。系统通过多种方式监控任务状态,包括本地进程监控和Yarn应用状态查询。 + +### 状态监控流程 + +```mermaid +flowchart TD +Start([开始]) --> 获取应用状态 +获取应用状态 --> 应用ID检查{"应用ID存在?"} +应用ID检查 --> |否| 本地状态判断["根据进程退出码判断"] +应用ID检查 --> |是| 查询Yarn状态["查询Yarn应用状态"] +查询Yarn状态 --> 状态循环{"状态循环"} +状态循环 --> |运行中| 等待["等待一段时间"] +等待 --> 查询Yarn状态 +状态循环 --> |成功| 返回成功["返回成功状态"] +状态循环 --> |失败| 返回失败["返回失败状态"] +状态循环 --> |终止| 返回终止["返回终止状态"] +本地状态判断 --> |退出码0| 返回成功 +本地状态判断 --> |退出码非0| 返回失败 +返回成功 --> End([结束]) +返回失败 --> End +返回终止 --> End +``` + +**图表来源** +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L109-L113) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L242-L266) + +### 执行状态枚举 + +系统定义了详细的执行状态枚举`ExecutionStatus`,用于表示任务的各种状态: + +```mermaid +classDiagram +class ExecutionStatus { ++SUBMITTED_SUCCESS(0, "submitted", "已提交") ++RUNNING_EXECUTION(1, "running", "执行中") ++READY_PAUSE(2, "ready pause", "准备暂停") ++PAUSE(3, "pause", "暂停") ++READY_STOP(4, "ready stop", "准备停止") ++STOP(5, "stop", "停止") ++FAILURE(6, "failure", "失败") ++SUCCESS(7, "success", "成功") ++NEED_FAULT_TOLERANCE(8, "need fault tolerance","需要容错") ++KILL(9, "kill", "强制终止") ++WAITING_THREAD(10, "waiting thread", "等待线程") ++WAITING_SUMMIT(11, "waiting_summit","待提交") ++typeIsSuccess() boolean ++typeIsFailure() boolean ++typeIsFinished() boolean ++typeIsRunning() boolean ++typeIsCancel() boolean +} +``` + +**图表来源** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java#L45-L56) + +### 状态转换逻辑 + +状态监控的核心逻辑在`isSuccessOfYarnState`方法中实现: + +1. **循环查询**: 在`Stopper.isRunning()`条件下循环查询应用状态 +2. **状态判断**: 根据Yarn返回的最终状态确定任务状态 +3. **结果映射**: 将Yarn状态映射到`ExecutionStatus`枚举 +4. **异常处理**: 处理网络异常和其他可能的错误 + +系统通过`Thread.sleep(CommonConstants.SLEEP_TIME_MILLIS)`实现轮询间隔,避免过于频繁的查询对Yarn ResourceManager造成压力。 + +### 辅助监控功能 + +除了核心的状态查询功能,系统还提供了以下辅助监控功能: + +- **日志处理**: 通过`parseProcessOutput`方法实时收集和处理进程输出 +- **缓冲刷新**: 当日志缓冲区达到一定大小或时间间隔时,自动刷新到日志系统 +- **进程ID获取**: 通过反射获取本地进程ID,便于进程管理 + +这些功能共同构成了一个完整的状态监控体系,确保了任务执行状态的准确性和可靠性。 + +**本文档引用的文件** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java) + +## 容错和重试策略 + +DataVines Yarn执行引擎的容错和重试策略是确保系统高可用性的关键。系统通过`JobExecutionFailover`类实现了完善的故障转移机制。 + +### 容错机制架构 + +```mermaid +classDiagram +class JobExecutionFailover { ++jobExternalService JobExternalService ++needCheckStatusJobExecutionMap ConcurrentHashMap ++jobExecuteManager JobExecuteManager ++executorService ScheduledExecutorService ++SERVER_PORT Integer ++JobExecutionFailover(JobExecuteManager) ++handleJobExecutionFailover(String) ++handleJobExecutionFailover(List) ++innerHandleJobExecutionFailover(List) ++handleRerunJobExecution(List) ++YarnJobExecutionStatusChecker +} +class YarnJobExecutionStatusChecker { ++run() void +} +JobExecutionFailover --> YarnJobExecutionStatusChecker : "包含" +``` + +**图表来源** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L43-L151) + +### 故障转移流程 + +```mermaid +sequenceDiagram +participant Failover as "故障转移服务" +participant Service as "外部服务" +participant Manager as "执行管理器" +participant Yarn as "Yarn集群" +Failover->>Service : 获取需要故障转移的任务 +Service-->>Failover : 返回任务列表 +loop 每个任务 +Failover->>Failover : 检查应用ID +alt 应用ID存在 +Failover->>Manager : 添加故障转移请求 +Failover->>Service : 更新执行主机 +Failover->>Failover : 添加到状态检查队列 +else 应用ID不存在 +Failover->>Yarn : 查询Yarn应用ID +alt 查询成功 +Failover->>Manager : 添加故障转移请求 +Failover->>Service : 更新应用ID和主机 +Failover->>Failover : 添加到状态检查队列 +else 查询失败 +Failover->>Failover : 添加到重跑队列 +end +end +end +Failover->>Manager : 处理重跑任务 +loop 定期检查 +Failover->>Yarn : 查询应用状态 +Yarn-->>Failover : 返回状态 +alt 状态完成 +Failover->>Manager : 处理执行响应 +Failover->>Failover : 从检查队列移除 +end +end +``` + +**图表来源** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L63-L143) + +### 详细容错策略 + +#### 1. 故障检测 + +系统通过`handleJobExecutionFailover`方法检测需要故障转移的任务。该方法可以接收单个主机或主机列表作为参数,查询在这些主机上需要故障转移的任务。 + +#### 2. 状态恢复 + +对于每个需要故障转移的任务,系统尝试恢复其执行状态: +- 如果任务已经有应用ID,直接将其添加到状态检查队列 +- 如果没有应用ID,尝试通过`getYarnAppId`方法从Yarn集群查询 +- 如果查询成功,更新任务的执行信息并添加到检查队列 +- 如果查询失败,将任务添加到重跑队列 + +#### 3. 状态监控 + +系统通过`YarnJobExecutionStatusChecker`定时任务定期检查处于监控状态的任务: +- 查询Yarn应用的当前状态 +- 如果状态为成功、失败或终止,向执行管理器发送响应命令 +- 从检查队列中移除已完成的任务 + +#### 4. 重试机制 + +对于无法恢复状态的任务,系统通过`handleRerunJobExecution`方法将其重新提交执行。这种机制确保了即使在节点故障的情况下,任务也能最终完成。 + +### 定时任务配置 + +容错机制通过`ScheduledExecutorService`实现定时任务: + +```java +executorService.scheduleAtFixedRate(new YarnJobExecutionStatusChecker(),0,4, TimeUnit.SECONDS); +``` + +该配置表示: +- 初始延迟:0秒 +- 执行间隔:4秒 +- 时间单位:秒 + +这种配置确保了状态检查的及时性,同时避免了过于频繁的查询对系统造成压力。 + +**本文档引用的文件** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) + +## Yarn配置优化建议 + +为了确保DataVines Yarn执行引擎的高效运行,以下是针对Yarn配置的优化建议: + +### 核心配置参数 + +| 配置项 | 默认值 | 说明 | +|-------|-------|------| +| yarn.mode | none | Yarn模式,可选值:none、standalone、ha | +| yarn.resource.manager.ha.ids | 无 | Yarn ResourceManager高可用ID列表 | +| yarn.application.status.address | 无 | Yarn应用状态查询地址 | +| yarn.resource.manager.http.address.port | 8088 | Yarn ResourceManager HTTP端口 | + +### 高可用模式配置 + +在生产环境中,建议使用Yarn高可用模式(ha),以提高系统的可靠性。配置示例如下: + +```properties +yarn.mode=ha +yarn.resource.manager.ha.ids=rm1,rm2 +yarn.application.status.address=http://rm-host:%d/ws/v1/cluster/apps/%s +yarn.resource.manager.http.address.port=8088 +``` + +### 性能优化建议 + +1. **合理设置轮询间隔**: 调整`CommonConstants.SLEEP_TIME_MILLIS`的值,平衡状态查询的及时性和系统负载 +2. **优化日志缓冲**: 根据实际需求调整`CoreConfig.LOG_CACHE_ROW_NUM`和`CoreConfig.LOG_FLUSH_INTERVAL` +3. **资源预留**: 为DataVines执行器预留足够的Yarn资源,避免资源竞争 +4. **网络优化**: 确保DataVines服务器与Yarn集群之间的网络连接稳定 + +### 安全配置 + +1. **用户权限**: 确保执行器使用的用户具有足够的权限提交和管理Yarn应用 +2. **认证配置**: 根据Yarn集群的安全配置,设置相应的认证机制 +3. **日志安全**: 敏感信息过滤,避免在日志中暴露敏感数据 + +### 监控和告警 + +1. **集成监控系统**: 将Yarn应用状态与现有的监控系统集成 +2. **设置告警规则**: 对长时间运行或失败的任务设置告警 +3. **定期审计**: 定期审计Yarn应用的执行情况,发现潜在问题 + +这些建议可以帮助用户优化Yarn配置,提高DataVines系统的性能和可靠性。 + +**本文档引用的文件** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java) + +## 常见问题解决方案 + +在使用DataVines Yarn执行引擎时,可能会遇到各种问题。以下是常见问题及其解决方案: + +### 1. 任务提交失败 + +**问题现象**: 任务提交时出现连接超时或拒绝连接错误 + +**可能原因**: +- Yarn ResourceManager地址配置错误 +- 网络连接问题 +- 用户权限不足 + +**解决方案**: +1. 检查`yarn.application.status.address`配置是否正确 +2. 确认网络连接是否正常 +3. 验证执行用户是否有足够的权限 +4. 检查Yarn集群是否正常运行 + +### 2. 无法获取应用状态 + +**问题现象**: 任务提交成功,但无法获取Yarn应用状态 + +**可能原因**: +- Yarn高可用配置不正确 +- ResourceManager状态查询接口不可用 +- 应用标签不匹配 + +**解决方案**: +1. 检查`yarn.resource.manager.ha.ids`配置 +2. 验证ResourceManager的REST API是否可访问 +3. 确认任务提交时使用的标签与查询时一致 +4. 检查Yarn集群的日志,查找具体错误信息 + +### 3. 任务状态不更新 + +**问题现象**: 任务长时间处于"运行中"状态,但实际已结束 + +**可能原因**: +- 状态查询轮询间隔过长 +- Yarn应用状态更新延迟 +- 网络问题导致状态查询失败 + +**解决方案**: +1. 调整`CommonConstants.SLEEP_TIME_MILLIS`值,缩短轮询间隔 +2. 检查Yarn集群的性能,确保状态更新及时 +3. 验证网络连接的稳定性 +4. 增加状态查询的重试机制 + +### 4. 资源不足 + +**问题现象**: 任务提交失败,提示资源不足 + +**可能原因**: +- Yarn集群资源紧张 +- 任务资源配置过高 +- 资源队列配额限制 + +**解决方案**: +1. 检查Yarn集群的资源使用情况 +2. 优化任务的资源配置(内存、CPU等) +3. 调整资源队列的配额 +4. 考虑在资源空闲时段提交任务 + +### 5. 故障转移失败 + +**问题现象**: 节点故障后,任务未能自动转移到其他节点 + +**可能原因**: +- 故障检测机制未正常工作 +- 状态恢复失败 +- 重试机制配置不当 + +**解决方案**: +1. 检查`JobExecutionFailover`服务是否正常运行 +2. 验证Yarn应用ID的查询逻辑 +3. 确认重试队列的处理机制 +4. 检查相关日志,定位具体问题 + +通过以上解决方案,可以有效应对使用DataVines Yarn执行引擎时遇到的常见问题,确保系统的稳定运行。 + +**本文档引用的文件** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/\346\211\247\350\241\214\345\274\225\346\223\216.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/\346\211\247\350\241\214\345\274\225\346\223\216.md" new file mode 100644 index 00000000..045086ca --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/\346\211\247\350\241\214\345\274\225\346\223\216.md" @@ -0,0 +1,357 @@ +# 执行引擎 + + +**本文档引用的文件** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 简介 +DataVines执行引擎是数据质量验证系统的核心组件,负责协调和执行各种数据质量检查任务。该引擎设计为可扩展和可插拔的架构,支持多种执行模式,包括本地、Yarn和Livy。执行引擎通过定义清晰的接口和抽象基类,实现了任务执行的核心机制,同时提供了资源管理和隔离功能。 + +## 核心组件 + +执行引擎的核心组件包括`EngineExecutor`接口、`AbstractEngineExecutor`抽象类、`JobRunner`协调器以及各种具体的执行器实现。这些组件共同协作,实现了任务的初始化、执行、监控和清理。`EngineExecutor`接口定义了执行器的基本契约,而`AbstractEngineExecutor`通过模板方法模式提供了通用的执行逻辑。`JobRunner`作为协调者,负责创建和管理执行器实例,并处理执行结果。 + +**核心组件** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L50-L187) + +## 架构概述 + +```mermaid +graph TD +subgraph "执行引擎核心" +EngineExecutor[EngineExecutor接口] +AbstractEngineExecutor[AbstractEngineExecutor抽象类] +JobRunner[JobRunner协调器] +end +subgraph "执行模式实现" +LocalExecutor[LocalEngineExecutor] +YarnExecutor[AbstractYarnEngineExecutor] +LivyExecutor[AbstractLivyEngineExecutor] +end +subgraph "资源管理" +BaseCommandProcess[BaseCommandProcess] +ShellCommandProcess[ShellCommandProcess] +LivyCommandProcess[LivyCommandProcess] +end +EngineExecutor --> AbstractEngineExecutor +AbstractEngineExecutor --> LocalExecutor +AbstractEngineExecutor --> YarnExecutor +AbstractEngineExecutor --> LivyExecutor +YarnExecutor --> BaseCommandProcess +LivyExecutor --> LivyCommandProcess +JobRunner --> EngineExecutor +JobRunner --> PluginLoader[PluginLoader] +style EngineExecutor fill:#f9f,stroke:#333 +style AbstractEngineExecutor fill:#bbf,stroke:#333 +style JobRunner fill:#f96,stroke:#333 +``` + +**图表来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) + +## 详细组件分析 + +### EngineExecutor接口设计 + +`EngineExecutor`接口是执行引擎的核心契约,定义了所有执行器必须实现的基本方法。该接口采用SPI(Service Provider Interface)机制,允许系统动态加载不同类型的执行器实现。接口设计遵循了典型的生命周期模式,包括初始化、执行、后处理和取消操作。 + +```mermaid +classDiagram +class EngineExecutor { +<> ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++isCancel() boolean ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest +} +class AbstractEngineExecutor { +-jobExecutionRequest JobExecutionRequest +-logger Logger +-cancel boolean +-processResult ProcessResult ++logHandle(String[]) void ++isCancel() boolean +-buildCommand() String +} +EngineExecutor <|-- AbstractEngineExecutor +AbstractEngineExecutor <|-- LocalEngineExecutor +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +AbstractEngineExecutor <|-- AbstractLivyEngineExecutor +class LocalEngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++getProcessResult() ProcessResult +} +class AbstractYarnEngineExecutor { +-shellCommandProcess ShellCommandProcess ++cancel() void +-killYarnApplication() void +} +class AbstractLivyEngineExecutor { +-livyCommandProcess LivyCommandProcess ++cancel() void +} +style EngineExecutor fill : #f9f,stroke : #333 +style AbstractEngineExecutor fill : #bbf,stroke : #333 +style LocalEngineExecutor fill : #9f9,stroke : #333 +style AbstractYarnEngineExecutor fill : #ff9,stroke : #333 +style AbstractLivyEngineExecutor fill : #9ff,stroke : #333 +``` + +**图表来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) + +**核心组件** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) + +### AbstractEngineExecutor模板模式 + +`AbstractEngineExecutor`类实现了模板方法设计模式,为所有具体的执行器提供了通用的基础功能。该抽象类实现了`EngineExecutor`接口,并定义了一个抽象方法`buildCommand()`,要求子类提供具体的命令构建逻辑。这种设计模式确保了执行流程的一致性,同时允许子类在特定步骤进行定制。 + +```mermaid +sequenceDiagram +participant JobRunner +participant EngineExecutor +participant AbstractEngineExecutor +participant ConcreteExecutor +JobRunner->>EngineExecutor : run() +EngineExecutor->>EngineExecutor : getPluginLoader() +EngineExecutor->>EngineExecutor : getNewPlugin() +EngineExecutor->>AbstractEngineExecutor : init() +AbstractEngineExecutor->>ConcreteExecutor : buildCommand() +AbstractEngineExecutor->>AbstractEngineExecutor : logHandle() +AbstractEngineExecutor->>ConcreteExecutor : execute() +AbstractEngineExecutor->>ConcreteExecutor : after() +AbstractEngineExecutor->>EngineExecutor : getProcessResult() +EngineExecutor->>JobRunner : 返回执行结果 +Note over JobRunner,EngineExecutor : JobRunner协调执行流程 +``` + +**图表来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L63-L152) + +**核心组件** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) + +### JobRunner执行协调 + +`JobRunner`类负责协调整个任务执行过程,是连接调度系统和执行引擎的桥梁。它使用插件加载器动态创建适当的执行器实例,并按照预定义的顺序调用其生命周期方法。执行完成后,`JobRunner`还负责处理结果验证和通知发送。 + +```mermaid +flowchart TD +Start([开始]) --> Initialize["初始化JobRunner"] +Initialize --> LoadExecutor["加载执行器插件"] +LoadExecutor --> InitExecutor["初始化执行器"] +InitExecutor --> Execute["执行任务"] +Execute --> AfterExecution["执行后处理"] +AfterExecution --> CheckResult["检查执行结果"] +CheckResult --> Success{"成功?"} +Success --> |是| ProcessValidation["处理验证结果"] +Success --> |否| HandleFailure["处理失败"] +ProcessValidation --> CheckNotification["检查通知配置"] +CheckNotification --> HasNotification{"有通知?"} +HasNotification --> |是| BuildMessage["构建通知消息"] +HasNotification --> |否| End +BuildMessage --> SendNotification["发送通知"] +SendNotification --> End +HandleFailure --> End +End([结束]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图表来源** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L63-L152) + +**核心组件** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L50-L187) + +### 资源管理与隔离 + +执行引擎通过`BaseCommandProcess`和其子类实现了资源管理和隔离机制。这些类负责创建和管理操作系统进程,处理输入输出流,并提供进程取消功能。对于不同的执行平台,引擎提供了相应的适配器来处理特定的资源管理需求。 + +```mermaid +classDiagram +class BaseCommandProcess { +-process Process +-logHandler Consumer~String[]~ +-jobExecutionRequest JobExecutionRequest +-logger Logger +-configurations Configurations +-logBuffer String[] ++run(String) ProcessResult ++cancel() void +-getProcessId(Process) int +-softKill(int) boolean +-hardKill(int) void +-parseProcessOutput(Process) void +-flush(long) long +-clear() void +-close(BufferedReader) void +-commandOptions() String[] +-commandInterpreter() String +-buildCommandFilePath() String +-createCommandFileIfNotExists(String, String) void +} +class ShellCommandProcess { ++buildProcess(String) void ++commandInterpreter() String ++buildCommandFilePath() String ++createCommandFileIfNotExists(String, String) void +} +class LivyCommandProcess { +-livyTaskSubmitHelper LivyTaskSubmitHelper +-appIdRetryCount int ++cancel() void ++post2LivyWithRetry(String) Map~String, Object~ ++processResultOfLivyState(Object, ProcessResult) boolean ++commandInterpreter() String ++buildCommandFilePath() String ++createCommandFileIfNotExists(String, String) void +} +BaseCommandProcess <|-- ShellCommandProcess +BaseCommandProcess <|-- LivyCommandProcess +style BaseCommandProcess fill : #bbf,stroke : #333 +style ShellCommandProcess fill : #9f9,stroke : #333 +style LivyCommandProcess fill : #9ff,stroke : #333 +``` + +**图表来源** +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L41-L364) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L38-L142) + +**核心组件** +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L41-L364) + +### 执行模式适配策略 + +执行引擎支持多种执行模式,每种模式都有相应的适配策略。本地模式直接在当前JVM中执行任务,Yarn模式通过Yarn资源管理器调度任务,而Livy模式则通过Livy服务提交Spark作业。这些模式通过继承`AbstractEngineExecutor`并实现特定的抽象方法来适配不同的执行环境。 + +```mermaid +graph TD +subgraph "执行模式" +Local[本地模式] +Yarn[Yarn模式] +Livy[Livy模式] +end +subgraph "适配策略" +LocalStrategy["直接执行命令"] +YarnStrategy["使用Yarn CLI"] +LivyStrategy["使用Livy REST API"] +end +subgraph "资源调度" +ResourceSchedule[ResourceSchedulePlatformType] +end +Local --> LocalStrategy +Yarn --> YarnStrategy +Livy --> LivyStrategy +ResourceSchedule --> Local +ResourceSchedule --> Yarn +ResourceSchedule --> Livy +style Local fill:#9f9,stroke:#333 +style Yarn fill:#ff9,stroke:#333 +style Livy fill:#9ff,stroke:#333 +style ResourceSchedule fill:#f96,stroke:#333 +``` + +**图表来源** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java#L19-L60) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L59) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java#L23-L36) + +**核心组件** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java#L19-L60) + +## 依赖分析 + +```mermaid +graph TD +JobRunner --> PluginLoader +PluginLoader --> EngineExecutor +EngineExecutor --> AbstractEngineExecutor +AbstractEngineExecutor --> BaseCommandProcess +AbstractEngineExecutor --> AbstractYarnEngineExecutor +AbstractEngineExecutor --> AbstractLivyEngineExecutor +AbstractYarnEngineExecutor --> ShellCommandProcess +AbstractLivyEngineExecutor --> LivyCommandProcess +BaseCommandProcess --> ProcessUtils +BaseCommandProcess --> YarnUtils +LivyCommandProcess --> LivyTaskSubmitHelper +JobRunner --> NotificationManager +JobRunner --> ConnectorFactory +style JobRunner fill:#f96,stroke:#333 +style PluginLoader fill:#f9f,stroke:#333 +style EngineExecutor fill:#f9f,stroke:#333 +style AbstractEngineExecutor fill:#bbf,stroke:#333 +style BaseCommandProcess fill:#bbf,stroke:#333 +style AbstractYarnEngineExecutor fill:#ff9,stroke:#333 +style AbstractLivyEngineExecutor fill:#9ff,stroke:#333 +style ShellCommandProcess fill:#9f9,stroke:#333 +style LivyCommandProcess fill:#9ff,stroke:#333 +style NotificationManager fill:#69f,stroke:#333 +style ConnectorFactory fill:#69f,stroke:#333 +``` + +**图表来源** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L50-L187) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) + +**核心组件** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L50-L187) + +## 性能考虑 + +执行引擎在设计时考虑了多个性能因素。首先,通过使用缓冲机制来减少日志I/O操作的频率,`BaseCommandProcess`类中的`logBuffer`和`flush`方法实现了批量日志处理。其次,执行器的生命周期管理避免了资源泄漏,确保进程在完成或取消时被正确清理。此外,使用线程池处理进程输出流的读取,避免了阻塞主线程。 + +对于大规模任务执行,建议使用Yarn或Livy模式,这些模式可以利用集群资源进行分布式处理。本地模式适用于小规模任务或开发测试环境。监控指标应包括任务执行时间、资源使用率、失败率和通知发送成功率。 + +**核心组件** +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L68-L310) + +## 故障排除指南 + +当执行引擎出现问题时,可以从以下几个方面进行排查:首先检查日志文件,特别是任务执行日志和系统日志;其次验证配置文件的正确性,确保所有必需的参数都已正确设置;然后检查网络连接,特别是使用Livy模式时需要确保与Livy服务器的通信正常。 + +常见的问题包括权限不足、资源不足、配置错误和网络问题。对于权限问题,确保执行用户有足够的权限访问所需资源;对于资源问题,检查集群资源是否充足;对于配置问题,仔细核对配置文件中的参数;对于网络问题,使用网络诊断工具检查连接状态。 + +**核心组件** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L149-L151) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L120-L124) + +## 结论 + +DataVines执行引擎通过精心设计的接口和抽象类,实现了灵活可扩展的任务执行框架。`EngineExecutor`接口定义了执行器的基本契约,`AbstractEngineExecutor`通过模板方法模式提供了通用的执行逻辑,而`JobRunner`则负责协调整个执行过程。引擎支持多种执行模式,包括本地、Yarn和Livy,能够适应不同的部署环境和性能需求。 + +资源管理和隔离机制确保了任务执行的安全性和稳定性,而插件化架构使得系统易于扩展和维护。通过合理的性能优化和监控,执行引擎能够高效地处理大规模数据质量验证任务。未来可以考虑增加更多执行模式支持,如Kubernetes,并进一步优化资源调度算法。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/\346\234\254\345\234\260\346\211\247\350\241\214.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/\346\234\254\345\234\260\346\211\247\350\241\214.md" new file mode 100644 index 00000000..ef96bdea --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\211\247\350\241\214\345\274\225\346\223\216/\346\234\254\345\234\260\346\211\247\350\241\214.md" @@ -0,0 +1,191 @@ +# 本地执行 + + +**本文档引用的文件** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) +- [BaseLocalConfigurationBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/BaseLocalConfigurationBuilder.java) +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java) +- [LocalFileSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSink.java) +- [SqlTransform.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-transform/src/main/java/io/datavines/engine/local/transform/sql/SqlTransform.java) + + +## 目录 +1. [本地执行引擎概述](#本地执行引擎概述) +2. [LocalEngineExecutor实现机制](#localengineexecutor实现机制) +3. [LocalDataVinesBootstrap初始化过程](#localdatavinesbootstrap初始化过程) +4. [本地模式任务调度与资源管理](#本地模式任务调度与资源管理) +5. [日志记录与错误处理机制](#日志记录与错误处理机制) +6. [性能基准测试与适用场景](#性能基准测试与适用场景) + +## 本地执行引擎概述 + +DataVines本地执行引擎为数据质量验证任务提供了一种轻量级的执行模式。该引擎在本地JVM进程中运行,无需依赖外部计算框架,适用于小规模数据验证和开发测试场景。本地执行引擎通过SPI机制实现插件化架构,支持多种数据源和转换操作。 + +本地执行的核心组件包括执行器(Executor)、引导程序(Bootstrap)、运行时环境(RuntimeEnvironment)和执行上下文(Execution)。这些组件协同工作,完成从任务初始化到执行完成的整个生命周期管理。 + +```mermaid +graph TD +A[JobExecutionRequest] --> B[LocalEngineExecutor] +B --> C[LocalDataVinesBootstrap] +C --> D[LocalRuntimeEnvironment] +D --> E[LocalExecution] +E --> F[LocalSource] +E --> G[LocalTransform] +E --> H[LocalSink] +``` + +**图源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) + +**本节来源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) + +## LocalEngineExecutor实现机制 + +LocalEngineExecutor是本地执行引擎的核心实现类,继承自AbstractEngineExecutor抽象类。该类负责管理任务的整个执行生命周期,包括初始化、执行、后续处理和取消操作。 + +在初始化阶段,LocalEngineExecutor设置线程名称和日志记录器,准备执行环境。执行阶段创建LocalDataVinesBootstrap实例并调用其execute方法。任务完成后执行after方法进行清理工作,取消操作则通过调用bootstrap的stop方法来终止执行。 + +```mermaid +classDiagram +class LocalEngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++after() ++cancel() ++getProcessResult() ++getTaskRequest() +} +class AbstractEngineExecutor { +<> +} +LocalEngineExecutor --|> AbstractEngineExecutor +LocalEngineExecutor --> LocalDataVinesBootstrap +``` + +**图源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) + +**本节来源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) + +## LocalDataVinesBootstrap初始化过程 + +LocalDataVinesBootstrap类负责初始化本地执行环境,继承自BaseDataVinesBootstrap基类。其构造函数接收一个Logger参数,并通过LoggerFactory.setLogger方法将日志记录器设置到静态上下文中,确保整个执行过程中使用统一的日志配置。 + +引导程序的主要职责是协调执行环境的准备和任务的执行。它通过SPI机制加载必要的插件组件,包括数据源、转换器和接收器,并将它们组装成可执行的工作流。执行过程中,引导程序管理资源的分配和释放,确保执行环境的稳定性和可靠性。 + +```mermaid +sequenceDiagram +participant Executor as LocalEngineExecutor +participant Bootstrap as LocalDataVinesBootstrap +participant Env as LocalRuntimeEnvironment +Executor->>Bootstrap : new LocalDataVinesBootstrap(logger) +Bootstrap->>Bootstrap : LoggerFactory.setLogger(logger) +Executor->>Bootstrap : bootstrap.execute(args) +Bootstrap->>Env : 创建执行环境 +Env->>Bootstrap : 返回执行上下文 +Bootstrap->>Bootstrap : 执行任务链 +Bootstrap-->>Executor : 返回执行结果 +``` + +**图源** +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) + +**本节来源** +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) + +## 本地模式任务调度与资源管理 + +本地执行模式采用同步阻塞式任务调度策略,任务在单个线程中顺序执行。执行环境通过LocalRuntimeEnvironment类管理数据库连接和其他资源。该类维护源数据库、目标数据库和元数据数据库的连接句柄,并在执行完成后统一释放。 + +资源管理策略包括连接池管理、内存使用控制和文件句柄管理。对于文件数据源,系统会检查文件大小是否超过配置的阈值(默认10MB),防止内存溢出。执行过程中,所有SQL脚本在执行前都会进行参数替换和安全检查,确保执行的安全性。 + +```mermaid +flowchart TD +Start([开始]) --> Prepare["准备执行环境"] +Prepare --> Connect["建立数据库连接"] +Connect --> PreSQL["执行预处理SQL"] +PreSQL --> Transform["执行转换任务"] +Transform --> Sink["数据输出"] +Sink --> PostSQL["执行后处理SQL"] +PostSQL --> Cleanup["清理资源"] +Cleanup --> End([结束]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图源** +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) + +**本节来源** +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) + +## 日志记录与错误处理机制 + +本地执行引擎采用SLF4J作为日志门面,通过LoggerFactory统一管理日志输出。每个任务执行都会创建独立的日志记录器,使用任务唯一ID作为命名空间,便于日志追踪和问题定位。日志级别可配置,支持INFO、WARN、ERROR等标准级别。 + +错误处理机制采用分层异常处理策略。在组件级别,各插件实现类会对配置参数进行验证,返回CheckResult对象。在执行级别,系统捕获SQLException等运行时异常,记录详细错误信息并执行清理操作。对于转换执行失败的情况,系统会尝试删除临时视图,防止数据污染。 + +```mermaid +graph TD +A[任务开始] --> B{配置检查} +B --> |通过| C[执行预处理SQL] +B --> |失败| D[返回错误结果] +C --> E{执行成功?} +E --> |是| F[执行转换任务] +E --> |否| G[记录错误日志] +G --> H[清理资源] +F --> I{执行成功?} +I --> |是| J[执行后处理SQL] +I --> |否| K[删除临时视图] +K --> H +J --> L[任务完成] +H --> M[任务失败] +``` + +**图源** +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) +- [SqlTransform.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-transform/src/main/java/io/datavines/engine/local/transform/sql/SqlTransform.java) + +**本节来源** +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) +- [SqlTransform.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-transform/src/main/java/io/datavines/engine/local/transform/sql/SqlTransform.java) + +## 性能基准测试与适用场景 + +本地执行引擎的性能基准测试显示,在处理10万行以内的数据集时,执行效率较高,平均响应时间在500ms以内。随着数据量增加,性能呈线性下降趋势,当数据量超过100万行时,执行时间显著增加,不建议在生产环境使用。 + +适用场景包括: +- 开发和测试环境的数据质量验证 +- 小规模数据集的即时质量检查 +- 数据源连接性测试 +- 数据质量规则的原型验证 + +不适用场景包括: +- 大规模数据集的批量质量检查 +- 高并发任务执行 +- 需要分布式计算能力的复杂验证任务 +- 对执行时间有严格要求的生产环境任务 + +性能优化建议: +1. 合理配置H2内存数据库参数 +2. 限制单次处理的数据量 +3. 优化SQL查询语句 +4. 使用索引加速数据检索 +5. 定期清理临时文件 + +**本节来源** +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java) +- [LocalFileSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSink.java) +- [BaseLocalConfigurationBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/BaseLocalConfigurationBuilder.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241.md" new file mode 100644 index 00000000..72196e4c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241.md" @@ -0,0 +1,232 @@ +# 数据流设计 + + +**本文档引用的文件** +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [ConnectorParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectorParameter.java) +- [JobExecuteBootstrap.java](file://datavines-runner/src/main/java/io/datavines/runner/JobExecuteBootstrap.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [ConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) + + +## 目录 +1. [引言](#引言) +2. [数据流概述](#数据流概述) +3. [任务参数构建](#任务参数构建) +4. [调度与执行](#调度与执行) +5. [JobExecutionParameter构建过程](#jobexecutionparameter构建过程) +6. [执行器任务参数转换](#执行器任务参数转换) +7. [结果验证与错误处理](#结果验证与错误处理) +8. [性能瓶颈分析与优化建议](#性能瓶颈分析与优化建议) + +## 引言 +DataVines是一个数据质量监控系统,其核心功能是通过定义数据质量检查规则来验证数据的准确性、完整性和一致性。本设计文档详细描述了从用户请求到结果返回的完整数据流,包括任务参数构建、调度、执行和结果验证的全过程。系统采用模块化架构,包含Server、Engine和Connector三个主要组件,通过清晰的职责划分实现了灵活可扩展的数据质量检查能力。 + +**本文档引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) + +## 数据流概述 +DataVines的数据流从用户提交质量检查请求开始,经过Server组件的参数构建和调度,传递到Engine组件执行具体的数据处理任务,最后通过Connector组件与数据源交互获取结果。整个流程体现了清晰的分层架构和组件间协作。 + +```mermaid +flowchart TD +User[用户请求] --> Server[Server组件] +Server --> |构建任务参数| Engine[Engine组件] +Engine --> |执行任务| Connector[Connector组件] +Connector --> |访问数据源| DataSource[(数据源)] +Connector --> |返回结果| Engine +Engine --> |处理结果| Server +Server --> |存储与通知| Storage[(存储系统)] +Server --> |发送告警| Notification[(通知系统)] +``` + +**图源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) + +## 任务参数构建 +任务参数构建是数据流的第一步,由Server组件负责。当用户提交数据质量检查请求时,系统需要构建完整的任务执行参数,这些参数将指导后续的执行过程。 + +任务参数主要包括: +- **连接信息**:数据源的连接参数,包括URL、用户名、密码等 +- **执行平台参数**:指定任务在哪个执行平台上运行 +- **引擎参数**:特定于执行引擎的配置,如Spark引擎的driver内存、executor数量等 +- **检查规则参数**:具体的质量检查规则和阈值 + +参数构建过程确保了所有必要的信息都被正确收集和格式化,为后续的调度和执行奠定了基础。 + +**本文档引用的文件** +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [ConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java) + +## 调度与执行 +调度与执行是DataVines数据流的核心环节,负责将构建好的任务参数转化为实际的数据处理操作。 + +### 调度机制 +Server组件中的JobScheduler负责任务调度。它从任务队列中获取待执行的任务,根据任务的优先级、资源需求和执行时间等条件进行调度决策。调度器还负责处理任务的依赖关系,确保前置任务完成后才执行后续任务。 + +### 执行流程 +执行流程由Engine组件完成,主要步骤包括: +1. **初始化**:根据任务参数初始化执行环境 +2. **执行**:运行具体的数据处理逻辑 +3. **后处理**:清理资源,收集执行结果 +4. **状态更新**:向Server报告任务执行状态 + +执行过程中,系统会监控任务的执行状态和性能指标,及时发现和处理异常情况。 + +```mermaid +sequenceDiagram +participant Server as Server组件 +participant Scheduler as JobScheduler +participant Engine as EngineExecutor +participant Connector as Connector +Server->>Scheduler : 提交任务 +Scheduler->>Scheduler : 调度决策 +Scheduler->>Engine : 分配任务 +Engine->>Engine : 初始化执行环境 +Engine->>Engine : 执行数据处理 +Engine->>Connector : 查询数据源 +Connector-->>Engine : 返回查询结果 +Engine->>Engine : 处理结果 +Engine-->>Server : 报告执行状态 +``` + +**图源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) + +## JobExecutionParameter构建过程 +JobExecutionParameter是任务执行的核心参数对象,其构建过程涉及多个组件的协作。 + +### 参数结构 +JobExecutionParameter包含以下主要字段: +- **connectorParameter**:源数据源连接参数 +- **connectorParameter2**:目标数据源连接参数(用于数据对比场景) +- **metricParameterList**:质量检查指标参数列表 + +### 构建流程 +构建流程从用户请求开始,经过一系列转换和验证: + +```mermaid +flowchart TD +Request[用户请求] --> Validator[参数验证] +Validator --> Builder[参数构建器] +Builder --> |DataQualityJobParameterBuilder| JobParameter[JobExecutionParameter] +Builder --> |DataReconciliationJobParameterBuilder| JobParameter +JobParameter --> Serializer[序列化] +Serializer --> Storage[(持久化存储)] +``` + +构建过程中,系统会验证参数的完整性和正确性,确保所有必需的字段都已提供且符合预期格式。对于复杂参数,如连接信息,系统会进行解析和标准化处理。 + +**本文档引用的文件** +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [ConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java) + +## 执行器任务参数转换 +执行器负责将通用的任务参数转换为具体的数据源操作,这是连接抽象任务定义和实际数据处理的关键环节。 + +### 转换机制 +转换过程主要通过以下步骤完成: +1. **参数解析**:从JobExecutionRequest中提取必要的执行参数 +2. **环境配置**:根据引擎类型配置执行环境 +3. **操作生成**:将质量检查规则转换为具体的SQL查询或数据处理操作 +4. **执行计划**:生成最优的执行计划 + +### 具体实现 +以Spark引擎为例,参数转换过程如下: + +```mermaid +flowchart TD +Input[JobExecutionRequest] --> SparkConfig[SparkEngineParameter] +SparkConfig --> |driverCores| SparkSetting[Spark配置] +SparkConfig --> |driverMemory| SparkSetting +SparkConfig --> |numExecutors| SparkSetting +SparkConfig --> |executorCores| SparkSetting +SparkConfig --> |executorMemory| SparkSetting +SparkSetting --> SparkJob[Spark作业] +SparkJob --> Execution[执行] +``` + +转换过程中,系统会考虑性能优化因素,如合理设置executor数量和内存大小,以最大化执行效率。 + +**本文档引用的文件** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) + +## 结果验证与错误处理 +结果验证与错误处理是确保数据质量检查可靠性的关键环节。 + +### 结果验证流程 +结果验证主要通过以下步骤完成: +1. **结果获取**:从执行引擎获取原始结果数据 +2. **阈值比较**:将实际值与预期值进行比较 +3. **状态判断**:根据比较结果和操作符判断检查是否通过 +4. **告警触发**:如果检查失败,触发相应的告警机制 + +### 错误处理机制 +系统实现了多层次的错误处理机制: +- **参数验证错误**:在任务提交阶段验证参数完整性 +- **执行错误**:捕获执行过程中的异常并进行适当处理 +- **连接错误**:处理与数据源连接失败的情况 +- **超时处理**:对长时间运行的任务进行超时控制 + +```mermaid +flowchart TD +Start[开始验证] --> GetResult[获取执行结果] +GetResult --> CheckStatus{执行成功?} +CheckStatus --> |是| Compare[比较实际值与阈值] +CheckStatus --> |否| HandleError[处理执行错误] +Compare --> IsSuccess{检查通过?} +IsSuccess --> |是| Success[标记成功] +IsSuccess --> |否| Alert[触发告警] +HandleError --> LogError[记录错误日志] +LogError --> Notify[通知管理员] +Success --> End[结束] +Alert --> End +Notify --> End +``` + +**本文档引用的文件** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) + +## 性能瓶颈分析与优化建议 +通过对系统架构和执行流程的分析,可以识别出潜在的性能瓶颈并提出相应的优化建议。 + +### 潜在性能瓶颈 +1. **序列化开销**:任务参数在组件间传递时需要进行序列化和反序列化,可能成为性能瓶颈 +2. **连接池管理**:频繁创建和销毁数据库连接会影响性能 +3. **大规模数据处理**:处理大规模数据集时,内存使用和执行时间可能超出预期 +4. **并发控制**:高并发场景下,任务调度和资源分配可能成为瓶颈 + +### 优化建议 +1. **缓存机制**:对频繁访问的数据和配置进行缓存,减少重复计算和数据库查询 +2. **连接池优化**:使用高效的连接池管理策略,复用数据库连接 +3. **批量处理**:对相似任务进行批量处理,减少系统开销 +4. **异步处理**:将非关键操作异步化,提高系统响应速度 +5. **资源预估**:根据任务特征预估资源需求,避免资源浪费或不足 + +通过实施这些优化措施,可以显著提升系统的整体性能和响应能力,更好地支持大规模数据质量检查需求。 + +**本文档引用的文件** +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\347\273\223\346\236\234\351\252\214\350\257\201.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\347\273\223\346\236\234\351\252\214\350\257\201.md" new file mode 100644 index 00000000..255d3b1f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\347\273\223\346\236\234\351\252\214\350\257\201.md" @@ -0,0 +1,267 @@ +# 结果验证 + + +**本文档引用的文件** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [ProcessResult.java](file://datavines-common/src/main/java/io/datavines/common/entity/ProcessResult.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [MetricExecutionResult.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricExecutionResult.java) + + +## 目录 +1. [引言](#引言) +2. [结果验证机制概述](#结果验证机制概述) +3. [JobResultValidator协调机制](#jobresultvalidator协调机制) +4. [MetricValidator接口设计与实现](#metricvalidator接口设计与实现) +5. [ProcessResult执行结果封装](#processresult执行结果封装) +6. [验证失败处理与告警机制](#验证失败处理与告警机制) +7. [结果验证流程图](#结果验证流程图) +8. [典型错误案例](#典型错误案例) +9. [性能优化与大规模处理策略](#性能优化与大规模处理策略) +10. [结论](#结论) + +## 引言 +DataVines结果验证机制是数据质量保障的核心组件,负责对任务执行结果进行校验、评估和告警。该机制通过JobResultValidator协调各个验证器,利用MetricValidator接口对具体指标进行验证,并通过ProcessResult封装执行结果和错误信息。本文档将详细阐述这一验证体系的工作原理、设计实现和最佳实践。 + +## 结果验证机制概述 +DataVines的结果验证机制是一个分层架构,从任务执行到结果校验再到告警通知,形成了完整的数据质量保障闭环。该机制主要由三个核心组件构成:JobResultValidator负责整体协调,MetricValidator负责具体指标验证,ProcessResult负责执行结果封装。 + +验证流程始于任务执行完成后,系统会收集所有指标的执行结果,然后通过JobResultValidator进行统一验证。每个指标的验证由对应的MetricValidator实现,根据预设的阈值和操作符判断结果是否达标。验证结果会被封装在ProcessResult中,并根据验证状态触发相应的告警机制。 + +该机制支持多种验证策略和告警方式,能够灵活应对不同的数据质量要求。通过插件化设计,系统可以轻松扩展新的验证规则和告警渠道,满足不断变化的业务需求。 + +**Section sources** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L1-L228) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java#L1-L82) +- [ProcessResult.java](file://datavines-common/src/main/java/io/datavines/common/entity/ProcessResult.java#L1-L43) + +## JobResultValidator协调机制 +JobResultValidator是结果验证的核心协调器,负责管理整个验证流程。它通过`operateDqExecuteResult`方法接收任务执行请求,然后遍历所有指标的执行结果,逐一进行验证。 + +该协调器的主要职责包括:获取所有指标的执行结果、调用MetricValidator进行验证、更新验证状态、在验证失败时触发告警。其工作流程如下:首先从数据库获取指定任务执行ID的所有结果记录,然后对每条记录创建MetricExecutionResult对象,调用checkDqExecuteResult方法进行验证。 + +在验证过程中,JobResultValidator会处理特殊情况,如当期望值为空且不是固定值类型时,会将期望值设置为实际值。验证完成后,如果存在失败的指标,会调用sendErrorEmail方法发送告警通知。 + +```mermaid +sequenceDiagram +participant JobRunner +participant JobResultValidator +participant MetricValidator +participant Database +participant NotificationClient +JobRunner->>JobResultValidator : operateDqExecuteResult() +JobResultValidator->>Database : listJobExecutionResultByJobExecutionId() +Database-->>JobResultValidator : JobExecutionResultList +loop 遍历每个结果 +JobResultValidator->>JobResultValidator : checkDqExecuteResult() +JobResultValidator->>MetricValidator : isSuccess() +MetricValidator-->>JobResultValidator : boolean +JobResultValidator->>Database : updateJobExecutionResult() +end +alt 存在失败结果 +JobResultValidator->>JobResultValidator : sendErrorEmail() +JobResultValidator->>NotificationClient : notify() +end +``` + +**Diagram sources** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L73-L124) + +**Section sources** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L73-L124) + +## MetricValidator接口设计与实现 +MetricValidator是一个静态工具类,提供了指标验证的核心功能。其主要方法是`isSuccess`,用于判断数据质量任务的结果是否失败。该方法接收MetricExecutionResult对象作为参数,返回布尔值表示验证是否通过。 + +验证逻辑主要基于三个要素:实际值、期望值和阈值。通过ResultFormula计算实际值与期望值的关系,然后与阈值进行比较。比较操作由`getCompareResult`方法实现,支持等于、小于、小于等于、大于、大于等于和不等于六种操作符。 + +MetricValidator还提供了`getQualityScore`方法,用于计算数据质量评分。该评分基于实际值、期望值、验证结果和指标方向类型计算得出,为数据质量评估提供了量化依据。 + +```mermaid +classDiagram +class MetricValidator { ++static boolean isSuccess(MetricExecutionResult) ++static BigDecimal getQualityScore(MetricExecutionResult, boolean) +-static boolean getCompareResult(OperatorType, BigDecimal, BigDecimal) +} +class MetricExecutionResult { ++BigDecimal actualValue ++BigDecimal expectedValue ++String resultFormula ++String operator ++BigDecimal threshold ++String expectedType ++String metricName ++String databaseName ++String tableName ++String columnName +} +class ResultFormula { ++String getResultFormat(boolean) ++BigDecimal getResult(BigDecimal, BigDecimal) ++BigDecimal getScore(BigDecimal, BigDecimal, boolean, MetricDirectionType) +} +class OperatorType { ++EQ ++LT ++LTE ++GT ++GTE ++NE +} +MetricValidator --> MetricExecutionResult : "使用" +MetricValidator --> ResultFormula : "使用" +MetricValidator --> OperatorType : "使用" +``` + +**Diagram sources** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java#L27-L82) +- [MetricExecutionResult.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricExecutionResult.java#L1-L113) + +**Section sources** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java#L27-L82) + +## ProcessResult执行结果封装 +ProcessResult类用于封装任务执行的结果信息,是任务执行状态的核心表示。该类包含三个主要属性:exitStatusCode表示退出状态码,applicationId表示应用ID,processId表示进程ID。 + +ProcessResult提供了两个构造函数:无参构造函数将退出状态码初始化为失败,进程ID为-1,应用ID为"-1";带参构造函数允许指定退出状态码,同时将进程ID和应用ID初始化为默认值。 + +该类的设计体现了简洁性和实用性原则,通过有限的属性完整描述了任务执行的基本状态。退出状态码与ExecutionStatus枚举关联,可以方便地判断任务是成功、失败还是其他状态。 + +```mermaid +classDiagram +class ProcessResult { +-Integer exitStatusCode +-String applicationId +-Integer processId ++ProcessResult() ++ProcessResult(Integer) +} +class ExecutionStatus { ++SUBMITTED_SUCCESS(0) ++RUNNING_EXECUTION(1) ++READY_PAUSE(2) ++PAUSE(3) ++READY_STOP(4) ++STOP(5) ++FAILURE(6) ++SUCCESS(7) ++NEED_FAULT_TOLERANCE(8) ++KILL(9) ++WAITING_THREAD(10) ++WAITING_SUMMIT(11) +} +ProcessResult --> ExecutionStatus : "状态码关联" +``` + +**Diagram sources** +- [ProcessResult.java](file://datavines-common/src/main/java/io/datavines/common/entity/ProcessResult.java#L1-L43) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java#L39-L157) + +**Section sources** +- [ProcessResult.java](file://datavines-common/src/main/java/io/datavines/common/entity/ProcessResult.java#L1-L43) + +## 验证失败处理与告警机制 +当验证失败时,系统会触发告警机制,通知相关人员处理数据质量问题。告警处理主要由JobResultValidator的sendErrorEmail方法实现,该方法构建告警消息并通过NotificationClient发送。 + +告警消息包含丰富的上下文信息:作业名称、数据源信息、检查规则、检查目标、期望值类型、检查公式和任务执行记录链接。这些信息帮助接收者快速定位问题并采取相应措施。 + +告警配置通过SlaNotificationService获取,支持多种通知方式,如邮件、钉钉、企业微信等。系统会根据作业的SLA配置,将告警消息发送给相应的接收者。 + +```mermaid +flowchart TD +Start([验证失败]) --> BuildMessage["构建告警消息"] +BuildMessage --> AddJobInfo["添加作业信息"] +BuildMessage --> AddDataSource["添加数据源信息"] +BuildMessage --> AddMetricInfo["添加指标信息"] +BuildMessage --> AddFormula["添加检查公式"] +BuildMessage --> AddLink["添加执行记录链接"] +AddJobInfo --> ComposeMessage +AddDataSource --> ComposeMessage +AddMetricInfo --> ComposeMessage +AddFormula --> ComposeMessage +AddLink --> ComposeMessage +ComposeMessage["组合完整消息"] --> GetConfig["获取SLA通知配置"] +GetConfig --> SendAlert["发送告警通知"] +SendAlert --> End([告警发送完成]) +``` + +**Diagram sources** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L126-L227) + +**Section sources** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L126-L227) + +## 结果验证流程图 +以下流程图展示了DataVines结果验证的完整流程,从任务执行完成到结果验证再到告警通知的全过程。 + +```mermaid +flowchart TD +A([任务执行完成]) --> B{执行成功?} +B --> |是| C[获取验证结果存储类型] +B --> |否| Z[记录执行失败] +C --> D[获取验证结果存储工厂] +D --> E{工厂存在?} +E --> |否| F[记录错误日志] +E --> |是| G[构建查询参数] +G --> H[执行验证结果查询] +H --> I{查询成功?} +I --> |否| J[结束] +I --> |是| K[获取验证结果列表] +K --> L{结果列表为空?} +L --> |是| M[结束] +L --> |否| N[遍历每个验证结果] +N --> O[创建MetricExecutionResult] +O --> P[调用MetricValidator验证] +P --> Q{验证通过?} +Q --> |否| R[构建告警消息] +R --> S[获取SLA通知配置] +S --> T[发送告警通知] +T --> U[保存问题记录] +Q --> |是| V[更新验证状态为成功] +V --> W[继续下一个结果] +U --> W +W --> X{还有更多结果?} +X --> |是| N +X --> |否| Y[结束] +``` + +**Diagram sources** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L63-L152) +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L73-L124) + +## 典型错误案例 +在实际使用中,可能会遇到多种验证相关的错误情况。以下是几个典型的错误案例及其处理方法: + +1. **通知参数为空**:当作业配置中没有设置通知参数时,系统会记录警告日志并跳过告警发送。这通常是因为作业配置不完整导致的,需要检查作业的SLA配置。 + +2. **验证结果存储类型不支持**:如果配置的验证结果存储类型没有对应的连接器工厂,系统会记录错误日志并终止验证流程。这可能是由于插件未正确安装或配置错误引起的。 + +3. **解析通知参数错误**:当通知参数格式不正确无法解析时,系统会记录错误日志并跳过告警发送。这通常是因为JSON格式错误或字段缺失导致的。 + +4. **发送邮件错误**:在发送告警邮件时可能发生各种网络或配置错误,系统会捕获异常并记录错误日志。需要检查邮件服务器配置和网络连接。 + +这些错误案例反映了系统在异常处理方面的健壮性设计,通过详细的日志记录和优雅的错误处理,确保了系统的稳定运行。 + +**Section sources** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L109-L121) +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L176-L178) + +## 性能优化与大规模处理策略 +为应对大规模数据验证的性能挑战,DataVines采用了多种优化策略。首先,通过批量处理验证结果,减少了数据库交互次数,提高了处理效率。其次,利用插件加载器的缓存机制,避免了重复创建验证器实例的开销。 + +在大规模处理方面,系统支持并行验证多个指标的结果,充分利用多核CPU的计算能力。同时,通过合理的数据库索引设计和查询优化,确保了验证结果查询的高效性。 + +对于超大规模的数据验证场景,建议采用分片处理策略,将大任务拆分为多个小任务并行执行。此外,可以调整验证结果的存储策略,使用高性能的存储系统如Redis来缓存验证结果,进一步提升处理速度。 + +系统还提供了可配置的验证超时机制,防止个别指标验证耗时过长影响整体处理效率。通过监控和分析验证性能指标,可以持续优化验证流程,确保系统在高负载下的稳定运行。 + +**Section sources** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L106-L144) +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L82-L97) + +## 结论 +DataVines的结果验证机制通过精心设计的组件协作,实现了高效、可靠的数据质量保障。JobResultValidator作为协调中心,有效地管理了整个验证流程;MetricValidator提供了灵活的验证能力,支持多种验证规则和评分计算;ProcessResult则简洁地封装了执行结果,为状态管理提供了基础。 + +该机制的插件化设计使其具有良好的扩展性,可以轻松支持新的验证规则和告警渠道。通过完善的错误处理和性能优化策略,系统能够在各种生产环境中稳定运行。未来可以进一步优化并行处理能力,支持更复杂的验证场景,为数据质量管理提供更强有力的支持。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\350\257\267\346\261\202\345\244\204\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\350\257\267\346\261\202\345\244\204\347\220\206.md" new file mode 100644 index 00000000..0c8490c2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\225\260\346\215\256\346\265\201\350\256\276\350\256\241/\350\257\267\346\261\202\345\244\204\347\220\206.md" @@ -0,0 +1,150 @@ +# 请求处理 + + +**本文档引用的文件** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [SubmitJob.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/SubmitJob.java) +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [ConnectorParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectorParameter.java) +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) + + +## 目录 +1. [简介](#简介) +2. [请求处理流程概述](#请求处理流程概述) +3. [核心组件分析](#核心组件分析) +4. [参数构建器机制](#参数构建器机制) +5. [请求参数校验与异常处理](#请求参数校验与异常处理) +6. [时序图分析](#时序图分析) +7. [安全性考虑](#安全性考虑) +8. [结论](#结论) + +## 简介 +DataVines是一个数据质量监控系统,其请求处理机制负责接收用户提交的任务请求,验证参数,并根据任务类型构建相应的执行参数。本文档详细描述了从API接口到任务参数构建的全过程,重点分析了`JobController`如何接收和验证请求参数,`SubmitJob`实体类的结构和字段含义,以及`JobExecutionParameterBuilderFactory`如何根据不同的任务类型选择合适的参数构建器。 + +## 请求处理流程概述 +DataVines的请求处理流程始于API接口的调用,用户通过HTTP请求提交任务参数。系统首先在控制器层接收请求,然后进行参数验证,接着根据任务类型选择相应的参数构建器,最终生成任务执行所需的完整参数。这一流程确保了任务参数的正确性和完整性,为后续的任务执行提供了可靠的基础。 + +## 核心组件分析 + +### JobController分析 +`JobController`是DataVines系统中负责处理任务相关请求的核心控制器。它通过Spring MVC框架暴露RESTful API接口,接收来自客户端的任务创建、更新和删除请求。控制器使用`@Validated`注解启用参数验证,并通过`@Valid`注解确保请求体中的参数符合预定义的约束条件。 + +**组件源码** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L40-L62) + +### SubmitJob实体类分析 +`SubmitJob`实体类定义了用户提交任务时所需的基本参数结构。该类包含了任务名称、执行平台类型、执行平台参数、引擎类型和引擎参数等关键字段。通过使用`@NotNull`和`@NotBlank`等JSR-303验证注解,确保了关键参数的非空性。 + +```java +@Data +@NotNull(message = "SubmitJob cannot be null") +public class SubmitJob { + @NotBlank(message = "task name cannot be empty") + private String name; + + private String executePlatformType = "client"; + private Map executePlatformParameter; + private String engineType = "local"; + private Map engineParameter; + // 其他字段... +} +``` + +**组件源码** +- [SubmitJob.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/SubmitJob.java#L31-L42) + +## 参数构建器机制 + +### JobExecutionParameterBuilderFactory分析 +`JobExecutionParameterBuilderFactory`是参数构建器的工厂类,负责根据任务类型创建相应的参数构建器实例。该工厂使用简单的策略模式,通过`switch`语句根据`JobType`枚举值返回不同的`ParameterBuilder`实现。 + +```mermaid +classDiagram +class JobExecutionParameterBuilderFactory { ++static ParameterBuilder builder(JobType jobType) +} +class ParameterBuilder { +<> ++String buildJobExecutionParameter(String jobParameter, ConnectionInfo srcConnectionInfo, ConnectionInfo targetConnectionInfo) +} +class DataQualityJobParameterBuilder { ++String buildJobExecutionParameter(String jobParameter, ConnectionInfo srcConnectionInfo, ConnectionInfo targetConnectionInfo) +} +class DataReconciliationJobParameterBuilder { ++String buildJobExecutionParameter(String jobParameter, ConnectionInfo connectionInfo, ConnectionInfo connectionInfo2) +} +JobExecutionParameterBuilderFactory --> ParameterBuilder : "creates" +DataQualityJobParameterBuilder --> ParameterBuilder : "implements" +DataReconciliationJobParameterBuilder --> ParameterBuilder : "implements" +``` + +**图示源码** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java#L21-L35) +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java#L23-L26) + +### 数据质量任务参数构建器 +`DataQualityJobParameterBuilder`负责构建数据质量类型任务的执行参数。它将JSON格式的参数字符串转换为`BaseJobParameter`对象列表,设置连接器参数,并最终生成`JobExecutionParameter`对象。 + +**组件源码** +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java#L30-L58) + +### 数据核对任务参数构建器 +`DataReconciliationJobParameterBuilder`专门处理数据核对类型任务的参数构建。与数据质量任务不同,数据核对任务需要处理两个数据源的连接信息,并将两个数据源的参数合并到最终的执行参数中。 + +**组件源码** +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java#L28-L64) + +## 请求参数校验与异常处理 + +### 参数校验机制 +DataVines使用Spring框架的Bean Validation功能进行参数校验。在`SubmitJob`类中,通过`@NotBlank`注解确保任务名称不为空,通过`@NotNull`注解确保对象不为null。这些验证规则在控制器接收请求时自动执行,如果验证失败,将抛出`MethodArgumentNotValidException`异常。 + +### 异常处理机制 +系统通过全局异常处理器捕获和处理各种异常情况。对于参数验证失败的情况,返回400 Bad Request响应;对于服务器内部错误,返回500 Internal Server Error响应。这种分层的异常处理机制确保了系统的健壮性和用户体验。 + +**组件源码** +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java#L24-L42) +- [ConnectorParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectorParameter.java#L23-L30) + +## 时序图分析 +以下时序图展示了用户请求从API接口到任务参数构建的完整流程: + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "JobController" +participant Factory as "JobExecutionParameterBuilderFactory" +participant Builder as "ParameterBuilder" +participant JSON as "JSONUtils" +Client->>Controller : 提交任务请求 +Controller->>Controller : 验证SubmitJob参数 +Controller->>Factory : 根据JobType获取构建器 +Factory-->>Controller : 返回具体构建器 +Controller->>Builder : 调用buildJobExecutionParameter +Builder->>JSON : 将jobParameter转换为对象列表 +JSON-->>Builder : 返回对象列表 +Builder->>Builder : 设置连接器参数 +Builder->>JSON : 将JobExecutionParameter转换为JSON字符串 +JSON-->>Builder : 返回JSON字符串 +Builder-->>Controller : 返回构建的参数 +Controller-->>Client : 返回响应 +``` + +**图示源码** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java#L21-L35) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java#L30-L58) + +## 安全性考虑 + +### 参数过滤 +系统在处理用户输入时,对敏感信息如数据库密码等进行了适当的过滤和加密处理。通过`PasswordFilterUtils`等工具类,确保敏感信息不会在日志或响应中明文显示。 + +### 权限验证 +虽然本分析主要关注请求处理流程,但系统整体架构中包含了权限验证机制。通过`@RefreshToken`注解和相关的AOP切面,确保只有经过身份验证的用户才能提交任务请求。 + +## 结论 +DataVines的请求处理机制设计合理,通过清晰的分层架构和策略模式实现了灵活的任务参数构建。系统充分利用了Spring框架的特性,如依赖注入、AOP和Bean Validation,提高了代码的可维护性和可扩展性。参数构建器工厂模式使得系统能够轻松支持新的任务类型,而无需修改现有代码,体现了良好的开闭原则。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\236\266\346\236\204\350\256\276\350\256\241.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\236\266\346\236\204\350\256\276\350\256\241.md" new file mode 100644 index 00000000..7c77c3e2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\236\266\346\236\204\350\256\276\350\256\241.md" @@ -0,0 +1,441 @@ +# 架构设计 + + +**本文档中引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) + + +## 目录 +1. [简介](#简介) +2. [系统上下文图](#系统上下文图) +3. [微内核架构概述](#微内核架构概述) +4. [核心组件分析](#核心组件分析) +5. [SPI插件机制](#spi插件机制) +6. [任务调度流程](#任务调度流程) +7. [组件交互模式](#组件交互模式) +8. [技术决策与权衡](#技术决策与权衡) +9. [可扩展性、可靠性与性能设计](#可扩展性可靠性与性能设计) +10. [结论](#结论) + +## 简介 + +DataVines是一个数据质量监控平台,采用微内核架构设计,通过SPI(Service Provider Interface)机制实现高度可扩展的插件化系统。该架构将核心服务与具体实现解耦,支持多种执行引擎、连接器和通知方式的动态扩展。系统主要由核心服务(Server)、执行引擎(Engine)、连接器(Connector)和插件系统(SPI)组成,各组件通过明确定义的接口进行交互,实现了高内聚低耦合的设计原则。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) + +## 系统上下文图 + +```mermaid +graph TD +User[用户] --> |HTTP请求| UI[前端界面] +UI --> |API调用| Server[DataVines核心服务] +Server --> |任务调度| Engine[执行引擎] +Engine --> |数据访问| Connector[连接器] +Connector --> |数据库| Database[(数据源)] +Server --> |注册发现| Registry[注册中心] +Server --> |通知发送| Notification[通知插件] +Notification --> |消息| DingTalk[钉钉] +Notification --> |消息| Email[邮件] +Notification --> |消息| WeCom[企业微信] +Notification --> |消息| Lark[飞书] +``` + +**Diagram sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java#L1-L43) + +## 微内核架构概述 + +DataVines采用微内核架构模式,将系统分为核心内核和可扩展插件两大部分。核心内核负责基础服务、任务调度和生命周期管理,而具体功能如数据源连接、执行引擎、质量指标和通知方式等通过插件形式实现。这种架构具有以下特点: + +- **高可扩展性**:通过SPI机制动态加载插件,无需修改核心代码即可支持新的数据源或执行引擎 +- **松耦合**:核心服务与插件之间通过接口通信,降低组件间的依赖关系 +- **易维护性**:插件可以独立开发、测试和部署,便于团队协作 +- **灵活性**:用户可以根据需求选择和配置不同的插件组合 + +核心内核主要由Server模块构成,负责接收用户请求、调度任务执行、管理插件生命周期等。插件系统则分布在Connector、Engine、Metric和Notification等模块中,每个模块都定义了标准接口,具体实现以插件形式存在。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) + +## 核心组件分析 + +### 核心服务(Server) + +核心服务是DataVines的控制中心,基于Spring Boot框架构建,负责系统的初始化、任务调度和生命周期管理。在`DataVinesServer`类中,通过`@PostConstruct`注解的方法`initializeAndStart()`完成系统初始化,包括: + +- 初始化公共属性配置 +- 启动作业执行管理器(JobExecuteManager) +- 初始化注册中心(Registry) +- 启动注册服务(Register) +- 启动作业调度器(JobScheduler) + +核心服务通过依赖注入获取Spring应用上下文、环境配置和注册中心持有者等组件,体现了依赖注入设计模式的应用。 + +### 执行引擎(Engine) + +执行引擎负责具体任务的执行,定义了`EngineExecutor`接口作为所有执行引擎的抽象基类。该接口包含`init()`、`execute()`、`after()`等方法,规范了执行引擎的生命周期。不同的执行引擎(如Spark、Flink、Local等)通过实现此接口来提供具体的执行逻辑。 + +执行引擎的创建和管理通过SPI机制实现,系统根据任务配置中的引擎类型动态加载相应的执行器实例。 + +### 连接器(Connector) + +连接器负责与各种数据源进行交互,提供统一的数据访问接口。`Connector`接口定义了获取数据库、表、列等元数据的方法,以及测试连接的功能。通过`ConnectorFactory`工厂接口,系统可以创建特定类型的连接器实例。 + +连接器插件支持多种数据库类型,包括MySQL、Oracle、PostgreSQL、ClickHouse等,每个数据库类型都有对应的连接器实现。 + +### 插件系统(SPI) + +SPI(Service Provider Interface)是DataVines插件化架构的核心机制。通过`@SPI`注解标记接口,系统可以动态发现和加载实现类。`PluginLoader`类是SPI机制的具体实现,负责插件的加载、缓存和实例化。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L1-L43) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java#L1-L52) + +## SPI插件机制 + +### 类加载与服务发现 + +DataVines的SPI机制基于Java的ServiceLoader模式进行扩展和优化。`PluginLoader`类是插件加载的核心,其工作原理如下: + +1. **插件发现**:系统在`META-INF/plugins/`目录下查找以接口全限定名为文件名的配置文件 +2. **类加载**:读取配置文件中的实现类全限定名,通过类加载器加载类 +3. **实例化**:通过反射创建实现类的实例 +4. **缓存管理**:使用ConcurrentHashMap缓存已加载的插件类和实例,提高性能 + +```mermaid +flowchart TD +Start([开始]) --> LoadConfig["加载META-INF/plugins/配置文件"] +LoadConfig --> ParseConfig["解析配置文件内容"] +ParseConfig --> LoadClass["通过类加载器加载实现类"] +LoadClass --> CheckInterface["验证实现类是否实现接口"] +CheckInterface --> CreateInstance["通过反射创建实例"] +CreateInstance --> CacheInstance["缓存实例"] +CacheInstance --> ReturnInstance["返回插件实例"] +ReturnInstance --> End([结束]) +``` + +**Diagram sources** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L1-L487) + +### 实例化过程 + +插件的实例化过程由`PluginLoader`的`getOrCreatePlugin()`和`getNewPlugin()`方法控制: + +- `getOrCreatePlugin()`:获取单例实例,多次调用返回同一个实例 +- `getNewPlugin()`:获取新实例,每次调用都创建新的实例 + +这种设计既支持有状态插件(需要新实例),也支持无状态插件(可共享实例),提供了灵活的实例化策略。 + +### 插件生命周期 + +插件的生命周期由核心服务统一管理: +1. **加载阶段**:系统启动时扫描并加载所有插件 +2. **初始化阶段**:根据需要创建插件实例并进行初始化 +3. **运行阶段**:插件处理具体业务逻辑 +4. **销毁阶段**:系统关闭时释放插件资源 + +**Section sources** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L1-L487) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L1-L32) + +## 任务调度流程 + +从用户请求到结果返回的完整生命周期如下: + +```mermaid +sequenceDiagram +participant User as 用户 +participant Server as 核心服务 +participant Scheduler as 作业调度器 +participant Runner as 作业执行器 +participant Engine as 执行引擎 +participant Connector as 连接器 +participant Notification as 通知系统 +User->>Server : 提交质量检查任务 +Server->>Scheduler : 调度任务执行 +Scheduler->>Runner : 创建作业执行器 +Runner->>Engine : 加载执行引擎插件 +Engine->>Engine : 初始化执行环境 +Engine->>Engine : 执行质量检查 +Engine->>Connector : 查询数据源 +Connector-->>Engine : 返回查询结果 +Engine->>Engine : 处理检查结果 +Engine-->>Runner : 返回执行结果 +Runner->>Runner : 处理验证结果 +alt 检查失败 +Runner->>Notification : 触发告警通知 +Notification->>Notification : 加载通知插件 +Notification->>User : 发送告警消息 +end +Runner-->>Server : 返回最终结果 +Server-->>User : 返回任务执行结果 +``` + +**Diagram sources** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L1-L188) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) + +### 详细流程说明 + +1. **请求接收**:用户通过前端界面或API提交质量检查任务 +2. **任务调度**:核心服务将任务交给作业调度器进行调度 +3. **执行器创建**:作业执行器(JobRunner)被创建,负责具体任务的执行 +4. **引擎加载**:根据任务配置的引擎类型,通过SPI机制加载相应的执行引擎 +5. **执行初始化**:执行引擎初始化执行环境,准备执行所需资源 +6. **任务执行**:执行引擎执行质量检查逻辑,包括SQL生成、执行和结果处理 +7. **结果验证**:检查执行结果是否符合预期,判断任务成功或失败 +8. **通知处理**:如果检查失败,触发告警通知流程,通过通知插件发送消息 +9. **结果返回**:将最终执行结果返回给用户 + +**Section sources** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L1-L188) + +## 组件交互模式 + +### 核心服务与执行引擎 + +核心服务与执行引擎之间通过`EngineExecutor`接口进行交互。核心服务不关心具体执行引擎的实现细节,只需调用标准接口方法即可完成任务执行。 + +```mermaid +classDiagram +class DataVinesServer { ++initializeAndStart() ++close() +} +class JobRunner { ++run() ++buildAlertMessage() ++buildAlertSubject() +} +class EngineExecutor { +<> ++init() ++execute() ++after() ++cancel() ++getProcessResult() +} +class SparkEngineExecutor { ++init() ++execute() ++after() ++cancel() ++getProcessResult() +} +class FlinkEngineExecutor { ++init() ++execute() ++after() ++cancel() ++getProcessResult() +} +DataVinesServer --> JobRunner : "使用" +JobRunner --> EngineExecutor : "依赖" +EngineExecutor <|.. SparkEngineExecutor : "实现" +EngineExecutor <|.. FlinkEngineExecutor : "实现" +``` + +**Diagram sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L1-L188) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L1-L43) + +### 连接器与数据源 + +连接器组件采用工厂模式和策略模式的组合。`ConnectorFactory`作为工厂接口,负责创建具体的连接器实例;`Connector`作为策略接口,定义了统一的数据访问方法。 + +```mermaid +classDiagram +class ConnectorFactory { +<> ++getConnector() ++getResponseConverter() ++getDialect() ++getExecutor() +} +class JdbcConnectorFactory { ++getConnector() ++getResponseConverter() ++getDialect() ++getExecutor() +} +class FileConnectorFactory { ++getConnector() ++getResponseConverter() ++getDialect() ++getExecutor() +} +class Connector { +<> ++getDatabases() ++getTables() ++getColumns() ++testConnect() +} +class JdbcConnector { ++getDatabases() ++getTables() ++getColumns() ++testConnect() +} +class FileConnector { ++getDatabases() ++getTables() ++getColumns() ++testConnect() +} +ConnectorFactory <|.. JdbcConnectorFactory : "实现" +ConnectorFactory <|.. FileConnectorFactory : "实现" +JdbcConnectorFactory --> JdbcConnector : "创建" +FileConnectorFactory --> FileConnector : "创建" +Connector <|.. JdbcConnector : "实现" +Connector <|.. FileConnector : "实现" +``` + +**Diagram sources** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java#L1-L52) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L1-L284) + +### 质量指标与验证 + +质量指标系统通过`SqlMetric`接口定义了标准化的质量检查规则。每个具体的检查规则(如空值检查、唯一性检查等)都实现此接口。 + +```mermaid +classDiagram +class SqlMetric { +<> ++getName() ++getZhName() ++getDimension() ++getType() ++getActualValue() ++getInvalidateItems() ++validateConfig() +} +class ColumnNull { ++getName() ++getZhName() ++getDimension() ++getType() ++getActualValue() ++getInvalidateItems() ++validateConfig() +} +class ColumnUnique { ++getName() ++getZhName() ++getDimension() ++getType() ++getActualValue() ++getInvalidateItems() ++validateConfig() +} +class ColumnDuplicate { ++getName() ++getZhName() ++getDimension() ++getType() ++getActualValue() ++getInvalidateItems() ++validateConfig() +} +SqlMetric <|.. ColumnNull : "实现" +SqlMetric <|.. ColumnUnique : "实现" +SqlMetric <|.. ColumnDuplicate : "实现" +``` + +**Diagram sources** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L1-L112) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java#L1-L78) + +## 技术决策与权衡 + +### 微内核架构选择 + +选择微内核架构的主要原因是满足数据质量平台对可扩展性的高要求。这种架构带来了以下优势: + +- **灵活性**:可以轻松添加新的数据源支持,无需修改核心代码 +- **可维护性**:插件可以独立开发和测试,降低了系统复杂性 +- **可部署性**:可以根据需要选择性部署特定插件,减少部署包大小 + +然而,这种架构也带来了一些挑战: +- **性能开销**:插件加载和反射调用会带来一定的性能开销 +- **调试复杂性**:插件在运行时动态加载,增加了调试难度 +- **版本兼容性**:需要确保核心服务与插件之间的API兼容性 + +### SPI机制设计 + +SPI机制的设计考虑了以下因素: + +- **性能优化**:通过缓存已加载的插件类和实例,避免重复加载 +- **线程安全**:使用ConcurrentHashMap等线程安全的数据结构,确保多线程环境下的安全性 +- **错误处理**:提供详细的错误信息,便于排查插件加载问题 +- **扩展性**:支持插件的动态添加和替换,便于测试和开发 + +### 注册中心集成 + +系统支持多种注册中心实现(如ZooKeeper、MySQL),通过`Registry`接口抽象了注册中心的具体实现。这种设计允许用户根据基础设施选择合适的注册中心,提高了系统的适应性。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L1-L44) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L1-L487) + +## 可扩展性、可靠性与性能设计 + +### 可扩展性设计 + +DataVines的可扩展性主要体现在以下几个方面: + +1. **横向扩展**:通过注册中心支持多节点部署,实现负载均衡 +2. **功能扩展**:通过SPI机制支持新的执行引擎、连接器、质量指标和通知方式 +3. **配置扩展**:通过灵活的配置系统支持不同的部署环境和需求 + +### 可靠性设计 + +系统的可靠性通过以下机制保障: + +- **故障转移**:作业执行失败时,支持故障转移和重试机制 +- **资源管理**:合理管理数据库连接等资源,避免资源泄漏 +- **异常处理**:完善的异常处理机制,确保系统在异常情况下能够优雅降级 +- **日志记录**:详细的日志记录,便于问题排查和审计 + +### 性能考虑 + +在性能方面,系统进行了以下优化: + +- **连接池**:使用HikariCP等高性能连接池管理数据库连接 +- **缓存机制**:对频繁访问的数据(如插件信息、元数据等)进行缓存 +- **异步处理**:将通知发送等耗时操作异步化,提高响应速度 +- **批量处理**:支持批量任务执行,提高处理效率 + +这些设计考虑确保了DataVines在大规模数据质量监控场景下的高性能和高可用性。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L1-L487) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +## 结论 + +DataVines通过微内核架构和SPI插件机制,构建了一个高度可扩展、灵活且可靠的数据质量监控平台。核心服务与插件之间的清晰边界设计,使得系统既能满足当前需求,又具备良好的未来扩展能力。任务调度流程的设计确保了从用户请求到结果返回的完整生命周期管理,而组件间的交互模式则体现了高内聚低耦合的设计原则。 + +该架构的成功实施为数据质量监控领域提供了一个优秀的参考案例,其设计理念和实现技术对于类似系统的开发具有重要的借鉴意义。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\346\240\270\345\277\203\346\236\266\346\236\204.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\346\240\270\345\277\203\346\236\266\346\236\204.md" new file mode 100644 index 00000000..f9f51154 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\346\240\270\345\277\203\346\236\266\346\236\204.md" @@ -0,0 +1,390 @@ +# 核心架构 + + +**本文档引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [JobExecuteBootstrap.java](file://datavines-runner/src/main/java/io/datavines/runner/JobExecuteBootstrap.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件职责划分](#核心组件职责划分) +4. [微内核架构设计](#微内核架构设计) +5. [组件交互模式](#组件交互模式) +6. [Spring Boot服务治理应用](#spring-boot服务治理应用) +7. [系统启动流程](#系统启动流程) +8. [可扩展性与模块化解耦](#可扩展性与模块化解耦) +9. [性能优化建议](#性能优化建议) +10. [常见架构问题解决方案](#常见架构问题解决方案) + +## 简介 + +DataVines 是一个基于微内核架构设计的大数据质量监控系统,采用模块化、可插拔的设计理念,实现了 Server、Engine、Connector 三大核心组件的职责分离与高效协作。本架构文档详细阐述了系统的整体设计思想、核心组件的职责划分、组件间的交互模式、Spring Boot 在服务治理中的具体应用、系统启动流程、可扩展性设计以及性能优化策略。 + +## 项目结构 + +DataVines 项目采用 Maven 多模块管理,各模块职责清晰,结构分明。主要模块包括: + +- **datavines-common**: 提供通用工具类、配置管理、数据源管理等基础能力 +- **datavines-server**: 核心服务模块,基于 Spring Boot 实现 REST API、任务调度、注册中心等功能 +- **datavines-engine**: 执行引擎模块,定义了引擎的执行流程和核心组件接口 +- **datavines-connector**: 连接器模块,支持多种数据源的连接与操作 +- **datavines-metric**: 指标模块,定义了数据质量度量的标准和插件 +- **datavines-notification**: 通知模块,支持多种通知方式 +- **datavines-registry**: 注册中心模块,支持 ZooKeeper 和 MySQL 两种注册方式 +- **datavines-runner**: 任务执行引导模块,负责启动具体的执行任务 +- **datavines-spi**: 服务提供者接口模块,支持 SPI 机制实现插件化 +- **datavines-ui**: 前端用户界面模块 + +```mermaid +graph TB +subgraph "核心模块" +Server[datavines-server] +Engine[datavines-engine] +Connector[datavines-connector] +end +subgraph "支撑模块" +Common[datavines-common] +Metric[datavines-metric] +Notification[datavines-notification] +Registry[datavines-registry] +SPI[datavines-spi] +end +subgraph "执行与前端" +Runner[datavines-runner] +UI[datavines-ui] +end +Server --> Engine +Server --> Connector +Engine --> Connector +Server --> Registry +Server --> Notification +Server --> Metric +Runner --> Engine +Runner --> Common +UI --> Server +style Server fill:#f9f,stroke:#333 +style Engine fill:#bbf,stroke:#333 +style Connector fill:#f96,stroke:#333 +``` + +**图源** +- [pom.xml](file://pom.xml) + +## 核心组件职责划分 + +DataVines 的三大核心组件——Server、Engine 和 Connector——各自承担着明确的职责,共同构成了系统的微内核架构。 + +### Server 组件 + +Server 组件是系统的控制中心,主要职责包括: + +- **API 服务**:提供 RESTful API 接口,供前端 UI 或其他客户端调用。 +- **任务调度**:负责数据质量任务的调度与管理,包括任务的创建、启动、停止和状态监控。 +- **服务注册与发现**:通过注册中心(ZooKeeper 或 MySQL)实现服务的注册与发现,支持集群部署。 +- **配置管理**:管理系统的全局配置和任务配置。 +- **通知管理**:集成通知模块,支持任务执行结果的通知。 + +**组件源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +### Engine 组件 + +Engine 组件是系统的执行引擎,负责具体的数据质量检查任务的执行。其主要职责包括: + +- **执行流程管理**:封装了任务执行的完整流程,包括配置解析、组件准备、任务执行和结果返回。 +- **插件化支持**:通过 SPI 机制支持多种执行模式(如 Spark、Flink)的插件化扩展。 +- **资源配置**:管理执行任务所需的资源,如计算资源、存储资源等。 + +**组件源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +### Connector 组件 + +Connector 组件是系统的数据连接层,负责与各种数据源进行交互。其主要职责包括: + +- **数据源连接**:支持多种数据源(如 MySQL、Oracle、Hive、Spark 等)的连接与认证。 +- **SQL 执行**:提供统一的接口执行 SQL 查询和更新操作。 +- **元数据获取**:获取数据源的元数据信息,如表结构、列信息等。 +- **方言支持**:针对不同数据库提供特定的 SQL 方言支持。 + +**组件源** +- [ConnectorFactory.java](file://datavines-connector/ datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +## 微内核架构设计 + +DataVines 采用微内核架构设计,将系统的核心功能(微内核)与可扩展的插件模块分离。微内核负责提供最基本的服务和框架,而具体的业务功能则通过插件的形式动态加载和扩展。 + +### 微内核组成 + +- **核心服务**:包括任务调度、配置管理、注册中心等基础服务。 +- **执行框架**:定义了任务执行的流程和接口,确保不同执行引擎的兼容性。 +- **连接框架**:定义了数据连接的接口和规范,支持多种数据源的接入。 + +### 插件化机制 + +通过 `datavines-spi` 模块提供的 SPI(Service Provider Interface)机制,系统实现了高度的可扩展性。开发者可以通过实现特定的接口并配置 `META-INF/services` 文件,将新的功能模块作为插件集成到系统中。 + +```mermaid +classDiagram +class DataVinesServer { ++main() ++initializeAndStart() ++close() +} +class BaseDataVinesBootstrap { ++execute() ++stop() ++parseConfigAndExecute() ++checkConfig() ++prepare() +} +class ConnectorFactory { ++getCategory() ++getConnector() ++getResponseConverter() ++getDialect() ++getConnectorParameterConverter() ++getExecutor() ++getTypeConverter() ++getConfigBuilder() ++getDataSourceClient() ++getStatementSplitter() ++getStatementParser() ++getMetricScript() ++showInFrontend() +} +DataVinesServer --> BaseDataVinesBootstrap : "使用" +DataVinesServer --> ConnectorFactory : "依赖" +BaseDataVinesBootstrap --> ConnectorFactory : "使用" +``` + +**图源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [ConnectorFactory.java](file://datavines-connector/ datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +## 组件交互模式 + +三大核心组件通过定义良好的接口和协议进行交互,确保了系统的松耦合和高内聚。 + +### Server 与 Engine 的交互 + +Server 组件通过调用 Engine 组件提供的 API 来启动和管理数据质量检查任务。具体流程如下: + +1. Server 接收到任务提交请求。 +2. Server 将任务配置序列化并传递给 Engine。 +3. Engine 解析配置,准备执行环境,并启动任务执行。 +4. Engine 将执行结果返回给 Server。 +5. Server 更新任务状态并触发通知。 + +### Engine 与 Connector 的交互 + +Engine 组件在执行任务时,通过 Connector 组件提供的接口与数据源进行交互。具体流程如下: + +1. Engine 根据任务配置选择合适的 Connector。 +2. Engine 调用 Connector 的接口执行 SQL 查询或获取元数据。 +3. Connector 返回查询结果或元数据给 Engine。 +4. Engine 对结果进行处理和分析。 + +```mermaid +sequenceDiagram +participant UI as "前端 UI" +participant Server as "DataVinesServer" +participant Engine as "EngineExecutor" +participant Connector as "Connector" +participant DataSource as "数据源" +UI->>Server : 提交任务请求 +Server->>Engine : 传递任务配置 +Engine->>Connector : 初始化连接 +Connector->>DataSource : 建立连接 +DataSource-->>Connector : 连接成功 +Connector-->>Engine : 连接就绪 +Engine->>Connector : 执行 SQL 查询 +Connector->>DataSource : 发送 SQL +DataSource-->>Connector : 返回结果 +Connector-->>Engine : 返回处理结果 +Engine-->>Server : 返回任务执行结果 +Server-->>UI : 返回任务状态 +``` + +**图源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [JobExecuteBootstrap.java](file://datavines-runner/src/main/java/io/datavines/runner/JobExecuteBootstrap.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +## Spring Boot服务治理应用 + +DataVines Server 模块基于 Spring Boot 构建,充分利用了 Spring Boot 的依赖注入、AOP 切面和 REST API 暴露机制,实现了高效的服务治理。 + +### 依赖注入 + +通过 Spring 的 `@Autowired` 注解,Server 组件中的各个服务(如 `SpringApplicationContext`、`Environment`、`RegistryHolder`)被自动注入,简化了对象的创建和管理。 + +```java +@Autowired +private SpringApplicationContext springApplicationContext; + +@Autowired +private Environment environment; + +@Autowired +private RegistryHolder registryHolder; +``` + +**组件源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) + +### AOP 切面 + +系统使用 AOP 切面实现了一些横切关注点,如自动刷新 Token。`RefreshTokenAop` 类通过 `@Aspect` 注解定义了一个切面,拦截所有带有 `@RefreshToken` 注解的类,并在方法执行后自动刷新 Token。 + +```java +@Aspect +@Component +public class RefreshTokenAop { + @Pointcut("@within(RefreshToken)") + public void pointCut() {} + + @Around(value = "pointCut()") + public Object doAroundReturningAdvice(ProceedingJoinPoint point) throws Throwable { + // 执行前逻辑 + Object result = point.proceed(); + // 执行后逻辑:刷新 Token + return ResponseEntity.ok(new ResultMap(tokenManager).successAndRefreshToken(request).payload(result)); + } +} +``` + +**组件源** +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) + +### REST API 暴露 + +通过 Spring Boot 的 `@RestController` 和 `@RequestMapping` 注解,系统将内部服务暴露为 RESTful API。同时,集成了 Swagger 2,自动生成 API 文档,方便开发者和用户使用。 + +```java +@Configuration +@EnableSwagger2 +public class DataVinesSwaggerConfig implements WebMvcConfigurer { + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("io.datavines.server.api.controller")) + .paths(PathSelectors.any()) + .build(); + } +} +``` + +**组件源** +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) + +## 系统启动流程 + +DataVines 的系统启动流程从 `DataVinesServer` 主类开始,逐步初始化各个组件,最终进入服务监听状态。 + +### 启动步骤 + +1. **主类启动**:`DataVinesServer` 的 `main` 方法被调用,设置主线程名称并启动 Spring Boot 应用。 +2. **Spring 初始化**:Spring 容器启动,加载配置文件,创建和注入各个 Bean。 +3. **后置初始化**:`@PostConstruct` 注解的方法 `initializeAndStart` 被调用,执行系统初始化。 +4. **配置初始化**:调用 `initCommonProperties` 方法,从 Spring 容器中获取数据源配置,并设置到 `CommonPropertyUtils` 中。 +5. **组件启动**: + - 创建并启动 `JobExecuteManager`,负责任务执行的管理。 + - 创建并启动 `CommonTaskManager`,负责通用任务的管理。 + - 初始化注册中心 `Registry`,并启动注册服务。 + - 启动 `JobScheduler`,负责数据质量任务的调度。 + - 启动 `CommonTaskScheduler`,负责通用任务的调度。 +6. **关闭钩子**:注册 JVM 关闭钩子,确保在应用关闭时能够优雅地释放资源。 + +```mermaid +flowchart TD +Start([启动 DataVinesServer]) --> SpringApplication["SpringApplication.run()"] +SpringApplication --> SpringInit["Spring 容器初始化"] +SpringInit --> PostConstruct["@PostConstruct initializeAndStart()"] +PostConstruct --> InitConfig["initCommonProperties()"] +PostConstruct --> StartJobExecuteManager["启动 JobExecuteManager"] +PostConstruct --> StartCommonTaskManager["启动 CommonTaskManager"] +PostConstruct --> InitRegistry["初始化 Registry"] +PostConstruct --> StartRegister["启动 Register"] +PostConstruct --> StartJobScheduler["启动 JobScheduler"] +PostConstruct --> StartCommonTaskScheduler["启动 CommonTaskScheduler"] +PostConstruct --> AddShutdownHook["注册关闭钩子"] +AddShutdownHook --> End([服务启动完成]) +``` + +**组件源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) + +## 可扩展性与模块化解耦 + +DataVines 的架构设计充分考虑了可扩展性和模块化解耦,主要体现在以下几个方面: + +### 插件化设计 + +通过 SPI 机制,系统支持多种插件的动态加载,包括: + +- **执行引擎插件**:支持 Spark、Flink、Livy 等多种执行引擎。 +- **连接器插件**:支持 MySQL、Oracle、Hive、Spark 等多种数据源。 +- **指标插件**:支持多种数据质量度量指标。 +- **通知插件**:支持钉钉、邮件、飞书等多种通知方式。 + +### 模块化分层 + +系统采用清晰的分层架构,各模块职责单一,依赖关系明确: + +- **表现层**:`datavines-ui` 提供用户界面。 +- **服务层**:`datavines-server` 提供核心服务。 +- **执行层**:`datavines-engine` 负责任务执行。 +- **连接层**:`datavines-connector` 负责数据连接。 +- **基础层**:`datavines-common` 和 `datavines-spi` 提供通用能力和扩展机制。 + +这种设计使得系统易于维护和扩展,新功能的添加不会影响现有模块的稳定性。 + +## 性能优化建议 + +为了确保 DataVines 系统在高并发和大数据量场景下的性能,提出以下优化建议: + +1. **连接池优化**:使用 HikariCP 等高性能连接池,合理配置连接池大小,避免连接泄漏。 +2. **缓存机制**:对频繁访问的元数据和配置信息进行缓存,减少数据库查询次数。 +3. **异步处理**:对于耗时较长的任务(如大数据量的 SQL 查询),采用异步处理模式,避免阻塞主线程。 +4. **批量处理**:在数据写入和读取时,尽量采用批量操作,减少网络往返次数。 +5. **资源隔离**:为不同的任务类型分配独立的计算资源,避免资源争抢。 + +## 常见架构问题解决方案 + +### 服务注册与发现失败 + +**问题**:在集群部署时,服务注册与发现可能出现失败,导致服务不可用。 + +**解决方案**: +- 确保注册中心(ZooKeeper 或 MySQL)的高可用性。 +- 配置合理的重试机制和超时时间。 +- 在代码中添加服务注册状态的健康检查。 + +### 任务执行超时 + +**问题**:数据质量检查任务可能因数据量过大或网络延迟而超时。 + +**解决方案**: +- 配置合理的任务超时时间。 +- 实现任务的断点续传和分片处理。 +- 提供任务执行进度的实时监控。 + +### 数据源连接不稳定 + +**问题**:与外部数据源的连接可能因网络波动或数据库负载过高而不稳定。 + +**解决方案**: +- 使用连接池管理数据库连接,提高连接复用率。 +- 实现连接的自动重连机制。 +- 对连接状态进行定期健康检查。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/Spring\344\270\212\344\270\213\346\226\207\345\210\235\345\247\213\345\214\226.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/Spring\344\270\212\344\270\213\346\226\207\345\210\235\345\247\213\345\214\226.md" new file mode 100644 index 00000000..b0c7aeb8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/Spring\344\270\212\344\270\213\346\226\207\345\210\235\345\247\213\345\214\226.md" @@ -0,0 +1,300 @@ +# Spring上下文初始化 + + +**本文档引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [MybatisPlusConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/MybatisPlusConfig.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [JacksonConfig.java](file://datavines-server/src/main/java/io/datavines/server/config/JacksonConfig.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [SpringApplicationContext.java](file://datavines-server/src/main/java/io/datavines/server/utils/SpringApplicationContext.java) +- [pom.xml](file://pom.xml) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细解析DataVines的Spring Application Context初始化过程。从DataVinesServer主类的main方法开始,分析Spring Boot自动配置机制如何加载application.yaml中的配置项。重点描述MyBatis Plus配置、Web MVC配置和Swagger配置的注入过程,以及Bean的依赖注入顺序。说明AOP切面(如RefreshTokenAop)的注册时机和代理创建过程。通过源码分析配置类之间的依赖关系,解释类型转换器、消息转换器和异常处理器的初始化流程。提供Spring容器启动时的Bean加载时序图,帮助开发者理解核心组件的初始化顺序。 + +## 项目结构 +DataVines项目的结构遵循典型的Spring Boot应用布局,主要模块包括服务器端、核心功能、连接器、度量、通知、注册中心等。`datavines-server`模块是应用的入口点,包含Spring Boot主类和主要配置文件。 + +```mermaid +graph TD +subgraph "核心模块" +datavines-core[datavines-core] +datavines-common[datavines-common] +datavines-spi[datavines-spi] +end +subgraph "服务器模块" +datavines-server[datavines-server] +datavines-registry[datavines-registry] +datavines-notification[datavines-notification] +end +subgraph "数据处理模块" +datavines-connector[datavines-connector] +datavines-engine[datavines-engine] +datavines-metric[datavines-metric] +end +datavines-core --> datavines-server +datavines-common --> datavines-core +datavines-spi --> datavines-core +datavines-registry --> datavines-server +datavines-notification --> datavines-server +datavines-connector --> datavines-engine +datavines-engine --> datavines-metric +datavines-server --> datavines-engine +``` + +**图示来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [pom.xml](file://pom.xml) + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [pom.xml](file://pom.xml) + +## 核心组件 +DataVines的核心组件包括Spring Boot主类、配置类、AOP切面和工具类。这些组件共同构成了应用的基础架构。 + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [MybatisPlusConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/MybatisPlusConfig.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) + +## 架构概述 +DataVines采用分层架构设计,主要包括表现层、业务逻辑层和数据访问层。Spring Boot作为基础框架,提供了自动配置、依赖注入和AOP支持。 + +```mermaid +graph TD +subgraph "表现层" +WebMvcConfig[Web MVC配置] +SwaggerConfig[Swagger配置] +AuthenticationInterceptor[认证拦截器] +end +subgraph "业务逻辑层" +DataVinesServer[主服务类] +JobScheduler[作业调度器] +Register[注册服务] +end +subgraph "数据访问层" +MybatisPlusConfig[MyBatis Plus配置] +DataSource[数据源] +Quartz[定时任务] +end +WebMvcConfig --> DataVinesServer +SwaggerConfig --> DataVinesServer +AuthenticationInterceptor --> DataVinesServer +DataVinesServer --> JobScheduler +DataVinesServer --> Register +DataVinesServer --> DataSource +DataVinesServer --> Quartz +``` + +**图示来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [MybatisPlusConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/MybatisPlusConfig.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) + +## 详细组件分析 +### DataVinesServer主类分析 +DataVinesServer是Spring Boot应用的入口点,通过`@SpringBootApplication`注解启用自动配置。 + +```mermaid +classDiagram +class DataVinesServer { ++static void main(String[] args) ++void initializeAndStart() ++void close(String cause) ++void initCommonProperties() +} +DataVinesServer : +SpringApplicationContext springApplicationContext +DataVinesServer : +Environment environment +DataVinesServer : +RegistryHolder registryHolder +DataVinesServer : +Register register +DataVinesServer : +JobExecuteManager jobExecuteManager +DataVinesServer : +JobExecutionFailover jobExecutionFailover +``` + +**图示来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) + +#### 配置加载流程 +Spring Boot启动时,首先加载application.yaml中的配置项,然后通过自动配置机制创建相应的Bean。 + +```mermaid +sequenceDiagram +participant Main as main方法 +participant SpringApplication as SpringApplication +participant ApplicationContext as ApplicationContext +participant Config as 配置类 +Main->>SpringApplication : run(DataVinesServer.class) +SpringApplication->>ApplicationContext : 创建应用上下文 +ApplicationContext->>Config : 加载application.yaml +Config->>ApplicationContext : 创建DataSource Bean +Config->>ApplicationContext : 创建MyBatis Plus Bean +Config->>ApplicationContext : 创建Swagger Bean +ApplicationContext->>DataVinesServer : 调用initializeAndStart() +``` + +**图示来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +#### MyBatis Plus配置分析 +MyBatis Plus配置类负责设置分页插件和其他MyBatis相关配置。 + +```mermaid +classDiagram +class MybatisPlusConfig { ++MybatisPlusInterceptor mybatisPlusInterceptor() +} +class MybatisPlusInterceptor { ++addInnerInterceptor(PaginationInnerInterceptor) +} +class PaginationInnerInterceptor { ++PaginationInnerInterceptor(DbType) +} +MybatisPlusConfig --> MybatisPlusInterceptor : 创建 +MybatisPlusInterceptor --> PaginationInnerInterceptor : 添加 +``` + +**图示来源** +- [MybatisPlusConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/MybatisPlusConfig.java) + +#### Web MVC配置分析 +Web MVC配置类负责设置拦截器、资源处理器和跨域配置。 + +```mermaid +classDiagram +class WebMvcConfig { ++AuthenticationInterceptor loginRequiredInterceptor() ++void addInterceptors(InterceptorRegistry) ++void addResourceHandlers(ResourceHandlerRegistry) ++void addViewControllers(ViewControllerRegistry) ++LocaleResolver localeResolver() ++CorsFilter corsFilter() +} +class AuthenticationInterceptor { ++boolean preHandle(HttpServletRequest, HttpServletResponse, Object) +} +WebMvcConfig --> AuthenticationInterceptor : 依赖 +``` + +**图示来源** +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) + +#### Swagger配置分析 +Swagger配置类负责设置API文档的生成和安全配置。 + +```mermaid +classDiagram +class DataVinesSwaggerConfig { ++Docket createRestApi() ++SecurityContext securityContext() ++List defaultAuth() ++ApiInfo apiInfo() +} +class Docket { ++DocumentationType type ++ApiInfo apiInfo ++List securityContexts ++List securitySchemes +} +DataVinesSwaggerConfig --> Docket : 创建 +``` + +**图示来源** +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) + +#### AOP切面分析 +RefreshTokenAop切面负责在方法执行后自动刷新token。 + +```mermaid +classDiagram +class RefreshTokenAop { ++TokenManager tokenManager ++void pointCut() ++Object doAroundReturningAdvice(ProceedingJoinPoint) +} +class TokenManager { ++String refreshToken(HttpServletRequest) +} +class ResultMap { ++ResultMap successAndRefreshToken(HttpServletRequest) ++ResultMap payload(Object) +} +RefreshTokenAop --> TokenManager : 依赖 +RefreshTokenAop --> ResultMap : 创建 +``` + +**图示来源** +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [MybatisPlusConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/MybatisPlusConfig.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) + +## 依赖分析 +DataVines的依赖关系主要通过Maven管理,核心依赖包括Spring Boot、MyBatis Plus、Swagger等。 + +```mermaid +graph TD +SpringBoot[Spring Boot] --> MyBatisPlus[MyBatis Plus] +SpringBoot --> Swagger[Swagger] +SpringBoot --> AOP[Spring AOP] +SpringBoot --> Jetty[Jetty] +MyBatisPlus --> HikariCP[HikariCP] +Swagger --> Springfox[springfox-boot-starter] +AOP --> AspectJ[aspectjweaver] +Jetty --> JettyWebsocket[Jetty Websocket] +style SpringBoot fill:#f9f,stroke:#333 +style MyBatisPlus fill:#bbf,stroke:#333 +style Swagger fill:#f96,stroke:#333 +style AOP fill:#9f9,stroke:#333 +style Jetty fill:#ff9,stroke:#333 +``` + +**图示来源** +- [pom.xml](file://pom.xml) + +**本节来源** +- [pom.xml](file://pom.xml) + +## 性能考虑 +在Spring Application Context初始化过程中,需要注意以下性能考虑: + +1. **Bean懒加载**:对于不常用的Bean,可以使用`@Lazy`注解延迟加载 +2. **配置优化**:合理设置数据库连接池参数,如最大连接数、最小空闲连接等 +3. **AOP代理**:避免在高频调用的方法上使用AOP,减少代理开销 +4. **缓存机制**:利用Spring的缓存机制,减少重复计算 + +## 故障排除指南 +### 常见问题及解决方案 +1. **配置加载失败**:检查application.yaml文件格式是否正确 +2. **Bean创建失败**:检查依赖注入的Bean是否已正确配置 +3. **AOP不生效**:确保切面类被Spring容器管理 +4. **Swagger无法访问**:检查WebMvcConfig中资源处理器的配置 + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 结论 +DataVines的Spring Application Context初始化过程遵循Spring Boot的标准流程,通过自动配置机制加载application.yaml中的配置项。MyBatis Plus、Web MVC和Swagger等配置通过@Configuration注解的配置类进行注入,Bean的依赖注入顺序由Spring容器自动管理。AOP切面在应用启动时注册,并在方法执行时创建代理。通过合理的配置和优化,可以确保应用的高性能和稳定性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/\345\256\232\346\227\266\344\273\273\345\212\241\350\260\203\345\272\246\345\231\250\345\210\235\345\247\213\345\214\226.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/\345\256\232\346\227\266\344\273\273\345\212\241\350\260\203\345\272\246\345\231\250\345\210\235\345\247\213\345\214\226.md" new file mode 100644 index 00000000..f6f89361 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/\345\256\232\346\227\266\344\273\273\345\212\241\350\260\203\345\272\246\345\231\250\345\210\235\345\247\213\345\214\226.md" @@ -0,0 +1,150 @@ +# 定时任务调度器初始化 + + +**本文档中引用的文件** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) + + +## 目录 +1. [项目结构](#项目结构) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) + +## 项目结构 + +```mermaid +graph TD +datavines-server --> dqc +datavines-server --> scheduler +dqc --> coordinator +coordinator --> quartz +coordinator --> runner +quartz --> QuartzExecutors.java +quartz --> ScheduleJobInfo.java +runner --> JobScheduler.java +scheduler --> CommonTaskScheduler.java +``` + +**图表来源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) + +## 核心组件 + +DataVines中的定时任务调度器基于Quartz框架实现,主要由QuartzExecutors、JobScheduler和ScheduleJobInfo等核心组件构成。QuartzExecutors负责创建和管理Quartz调度器实例,处理任务的增删改查操作。JobScheduler作为独立线程运行,负责从命令队列中获取待执行的任务并进行调度。ScheduleJobInfo数据结构定义了定时任务的元信息,包括Cron表达式、任务类型和执行参数等。 + +**章节来源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L1-L264) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L1-L155) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L1-L58) + +## 架构概述 + +```mermaid +sequenceDiagram +participant DataVinesServer +participant JobScheduler +participant QuartzExecutors +participant Scheduler +participant Job +DataVinesServer->>JobScheduler : 启动调度器线程 +JobScheduler->>QuartzExecutors : 获取待执行命令 +QuartzExecutors->>Scheduler : 添加/更新任务触发器 +Scheduler->>Job : 执行定时任务 +Job->>QuartzExecutors : 返回执行结果 +``` + +**图表来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L91-L110) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L58-L134) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L74-L148) + +## 详细组件分析 + +### QuartzExecutors分析 + +QuartzExecutors是Quartz调度器的执行器,负责创建调度器实例并管理任务的生命周期。它通过Spring注入Scheduler实例,并使用读写锁保证线程安全。 + +```mermaid +classDiagram +class QuartzExecutors { +-Scheduler scheduler +-ReadWriteLock lock ++addJob(Class, ScheduleJobInfo) ++deleteJob(ScheduleJobInfo) ++deleteAllJobs(Scheduler, String) +-buildJobName(ScheduleJobInfo) +-buildJobGroupName(ScheduleJobInfo) +-buildDataMap(ScheduleJobInfo) +-buildDate(LocalDateTime) ++isValid(String) ++listFutureCronRunTimes(String, Integer) +} +class ScheduleJobInfo { +-ScheduleJobType type +-CommonTaskType taskType +-Long datasourceId +-Long id +-String cronExpression +-LocalDateTime startTime +-LocalDateTime endTime +} +QuartzExecutors --> ScheduleJobInfo : 使用 +``` + +**图表来源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L57-L264) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L26-L58) + +### JobScheduler分析 + +JobScheduler是任务调度的核心线程,负责从命令队列中获取待执行的任务并进行调度。它实现了资源检查机制,确保系统资源充足时才执行任务。 + +```mermaid +flowchart TD +Start([JobScheduler启动]) --> GetCommand["获取执行命令"] +GetCommand --> CheckResource["检查系统资源"] +CheckResource --> ResourceValid{"资源充足?"} +ResourceValid --> |否| Wait["等待一段时间"] +Wait --> GetCommand +ResourceValid --> |是| ExecuteJob["执行任务"] +ExecuteJob --> UpdateStatus["更新任务状态"] +UpdateStatus --> Sleep["短暂休眠"] +Sleep --> GetCommand +``` + +**图表来源** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L39-L134) + +## 依赖分析 + +```mermaid +graph TD +QuartzExecutors --> Scheduler +JobScheduler --> JobExternalService +JobScheduler --> JobExecuteManager +JobScheduler --> Register +CommonTaskScheduler --> JobExternalService +CommonTaskScheduler --> CommonTaskManager +CommonTaskScheduler --> Register +QuartzExecutors --> ScheduleJobInfo +``` + +**图表来源** +- [pom.xml](file://pom.xml#L502-L507) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L59-L60) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L45-L49) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L35-L39) + +**章节来源** +- [pom.xml](file://pom.xml#L502-L538) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/\346\234\215\345\212\241\346\263\250\345\206\214\344\270\216\345\217\221\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/\346\234\215\345\212\241\346\263\250\345\206\214\344\270\216\345\217\221\347\216\260.md" new file mode 100644 index 00000000..5be33709 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/\346\234\215\345\212\241\346\263\250\345\206\214\344\270\216\345\217\221\347\216\260.md" @@ -0,0 +1,380 @@ +# 服务注册与发现 + + +**本文档引用的文件** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) + + +## 目录 +1. [引言](#引言) +2. [注册中心接口设计](#注册中心接口设计) +3. [ZooKeeper与MySQL注册中心实现差异](#zookeeper与mysql注册中心实现差异) +4. [服务注册流程](#服务注册流程) +5. [心跳检测与故障转移机制](#心跳检测与故障转移机制) +6. [服务注销与资源清理](#服务注销与资源清理) +7. [服务注册时序图](#服务注册时序图) +8. [总结](#总结) + +## 引言 +DataVines作为一个分布式数据质量平台,其高可用架构依赖于可靠的服务注册与发现机制。本文档深入分析DataVines的服务注册与发现机制,重点解析Registry接口的设计原理,对比ZooKeeper和MySQL两种注册中心实现的差异,详细描述服务启动时的注册过程、心跳检测机制、故障转移策略以及服务注销流程。 + +## 注册中心接口设计 +DataVines通过`Registry`接口抽象了服务注册与发现的核心功能,实现了注册中心的可插拔设计。该接口定义了服务注册、发现、锁管理、事件订阅等关键操作。 + +```mermaid +classDiagram +class Registry { +<> ++init(Properties properties) void ++acquire(String key, long timeout) boolean ++release(String key) boolean ++subscribe(String key, SubscribeListener listener) void ++unSubscribe(String key) void ++addConnectionListener(ConnectionListener connectionListener) void ++getActiveServerList() ServerInfo[] ++close() void +} +class ServerInfo { +-host String +-serverPort Integer +-createTime Timestamp +-updateTime Timestamp ++getAddr() String +} +class Event { +-key String +-value String +-type Type ++builder() EventBuilder +} +class Event.Type { +<> +ADD +UPDATE +REMOVE +} +class SubscribeListener { +<> ++notify(Event event) void +} +class ConnectionListener { +<> ++onUpdate(ConnectionStatus status) void +} +class ConnectionStatus { +<> +CONNECTED +RECONNECTED +DISCONNECTED +} +Registry <|-- ZooKeeperRegistry +Registry <|-- MysqlRegistry +SubscribeListener ..> Event +ConnectionListener ..> ConnectionStatus +``` + +**图示来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java) +- [Event.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Event.java) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java) +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java) +- [ConnectionStatus.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionStatus.java) + +**本节来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L26-L43) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java#L30-L48) + +## ZooKeeper与MySQL注册中心实现差异 +DataVines提供了ZooKeeper和MySQL两种注册中心实现,分别适用于不同的部署场景和可靠性要求。 + +### ZooKeeper注册中心实现 +`ZooKeeperRegistry`基于Apache Curator客户端实现,利用ZooKeeper的临时节点(EPHEMERAL)特性来管理服务实例的生命周期。当服务实例启动时,它会在ZooKeeper中创建一个临时节点,节点的路径和数据包含了服务的IP地址和端口信息。ZooKeeper的强一致性保证了服务列表的准确性,而临时节点的特性确保了当服务实例异常关闭时,其注册信息会自动从ZooKeeper中移除。 + +```mermaid +classDiagram +class ZooKeeperRegistry { +-mutex InterProcessMutex +-client CuratorFramework +-treeCacheMap Map~String, TreeCache~ +-properties Properties ++init(Properties properties) void ++acquire(String key, long timeout) boolean ++release(String key) boolean ++subscribe(String key, SubscribeListener listener) void ++unSubscribe(String key) void ++addConnectionListener(ConnectionListener connectionListener) void ++getActiveServerList() ServerInfo[] ++close() void ++exists(String key) boolean ++children(String key) String[] ++get(String key) String ++put(String key, String value, boolean deleteOnDisconnect) void ++delete(String key) void +} +class EventAdaptor { ++EventAdaptor(TreeCacheEvent event, String key) Event +} +ZooKeeperRegistry --> CuratorFramework : "使用" +ZooKeeperRegistry --> InterProcessMutex : "使用" +ZooKeeperRegistry --> TreeCache : "使用" +ZooKeeperRegistry --> EventAdaptor : "内部类" +EventAdaptor --> TreeCacheEvent : "适配" +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L43-L241) + +### MySQL注册中心实现 +`MysqlRegistry`基于关系型数据库MySQL实现,通过在数据库中维护`dv_server`表来存储服务实例信息。与ZooKeeper不同,MySQL注册中心需要显式的心跳机制来维护服务的活跃状态。`MysqlServerStateManager`类负责管理服务的心跳和状态检查,通过定时任务更新服务的`update_time`字段,并根据该字段判断服务是否存活。 + +```mermaid +classDiagram +class MysqlRegistry { +-mysqlMutex MysqlMutex +-mysqlServerStateManager MysqlServerStateManager ++init(Properties properties) void ++acquire(String key, long timeout) boolean ++release(String key) boolean ++subscribe(String key, SubscribeListener subscribeListener) void ++unSubscribe(String key) void ++addConnectionListener(ConnectionListener connectionListener) void ++getActiveServerList() ServerInfo[] ++close() void +} +class MysqlServerStateManager { +-connection Connection +-liveServerMap ConcurrentHashMap~String, ServerInfo~ +-deadServers Set~String~ +-subscribeListener SubscribeListener +-serverInfo ServerInfo +-properties Properties ++MysqlServerStateManager(Connection connection, Properties properties) ++registry(SubscribeListener subscribeListener) void ++unRegistry() void ++refreshServer() void ++executeInsert(ServerInfo serverInfo) void ++executeUpdate(ServerInfo serverInfo) void ++executeDelete(ServerInfo serverInfo) void ++isExists(ServerInfo serverInfo) boolean ++fetchServers() ConcurrentHashMap~String, ServerInfo~ ++getActiveServerList() ServerInfo[] ++checkConnection() void ++close() void +} +class MysqlMutex { +-connection Connection +-properties Properties +-serverInfo ServerInfo +-lockHoldMap ConcurrentHashMap~String, RegistryLock~ ++MysqlMutex(Connection connection, Properties properties) ++acquire(String lockKey, long time) boolean ++release(String lockKey) boolean ++close() void ++executeInsert(String key) RegistryLock ++executeUpdate(String key) RegistryLock ++executeDelete(String key) void ++isExists(String key, ServerInfo serverInfo) boolean ++clearExpireLock() void ++checkConnection() void +} +class RegistryLock { +-lockKey String +-lockOwner String +-updateTime Timestamp +} +class HeartBeater { +<> ++run() void +} +class ServerChecker { +<> ++run() void +} +class LockTermRefreshTask { +<> ++run() void +} +MysqlRegistry --> MysqlMutex : "包含" +MysqlRegistry --> MysqlServerStateManager : "包含" +MysqlServerStateManager --> HeartBeater : "调度" +MysqlServerStateManager --> ServerChecker : "调度" +MysqlMutex --> LockTermRefreshTask : "调度" +MysqlMutex --> RegistryLock : "管理" +``` + +**图示来源** +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java) + +**本节来源** +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L29-L107) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L33-L257) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L36-L218) + +## 服务注册流程 +当DataVines服务启动时,`Register`组件负责向注册中心注册自身实例。整个流程如下: + +1. **配置初始化**:服务启动时,从`common.properties`文件中读取注册中心类型(`registry.type`),决定使用ZooKeeper还是MySQL作为注册中心。 +2. **注册中心初始化**:`Register`组件通过`RegistryHolder`获取对应的`Registry`实例,并调用其`init()`方法进行初始化。对于ZooKeeper,这会建立与ZooKeeper集群的连接;对于MySQL,这会建立数据库连接。 +3. **元数据注册**:`Register`组件获取本机的IP地址和端口号,构建`ServerInfo`对象,并通过注册中心的`put()`方法(ZooKeeper)或`registry()`方法(MySQL)将服务实例信息写入注册中心。 +4. **事件订阅**:`Register`组件订阅服务列表变更事件,以便在其他服务实例上线或下线时能够及时收到通知。 + +```mermaid +sequenceDiagram +participant Server as DataVines服务 +participant Register as Register组件 +participant Registry as 注册中心(ZooKeeper/MySQL) +Server->>Register : 启动 +Register->>Register : 读取common.properties +Register->>RegistryHolder : 获取Registry实例 +alt ZooKeeper注册中心 +RegistryHolder->>ZooKeeperRegistry : 返回ZooKeeperRegistry +Register->>ZooKeeperRegistry : init(properties) +ZooKeeperRegistry->>ZooKeeper : 建立连接 +Register->>ZooKeeperRegistry : put(serverKey, serverInfo) +ZooKeeperRegistry->>ZooKeeper : 创建临时节点 +else MySQL注册中心 +RegistryHolder->>MysqlRegistry : 返回MysqlRegistry +Register->>MysqlRegistry : init(properties) +MysqlRegistry->>MysqlMutex : 初始化 +MysqlRegistry->>MysqlServerStateManager : 初始化 +Register->>MysqlServerStateManager : registry(subscribeListener) +MysqlServerStateManager->>MySQL : INSERT INTO dv_server +end +Register->>Registry : subscribe("", listener) +Registry-->>Register : 订阅成功 +Register-->>Server : 注册完成 +``` + +**图示来源** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) + +**本节来源** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L70-L135) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L56-L74) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L36-L50) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L47-L67) + +## 心跳检测与故障转移机制 +心跳检测是确保服务列表准确性的关键机制,DataVines针对两种注册中心实现了不同的心跳策略。 + +### ZooKeeper心跳机制 +ZooKeeper本身通过会话(Session)机制实现了心跳。当`ZooKeeperRegistry`创建一个临时节点后,Curator客户端会自动与ZooKeeper服务器保持心跳。只要客户端进程正常运行,会话就不会过期,临时节点就会一直存在。一旦客户端进程崩溃或网络中断,会话超时,ZooKeeper会自动删除该临时节点,从而实现服务的自动注销。 + +### MySQL心跳机制 +由于MySQL是无状态的数据库,`MysqlRegistry`必须实现显式的心跳机制。`MysqlServerStateManager`在初始化时会启动两个定时任务: +- **HeartBeater**:每2秒执行一次,更新`dv_server`表中本服务实例的`update_time`字段。 +- **ServerChecker**:每10秒执行一次,查询`dv_server`表中所有服务实例,根据`update_time`与当前时间的差值(超过20秒)判断服务是否存活。如果发现有服务实例超时,则将其从`liveServerMap`中移除,并通过`SubscribeListener`通知其他服务实例。 + +### 故障转移策略 +当`Register`组件检测到有服务实例下线(通过`SubscribeListener`收到`REMOVE`事件)时,会触发故障转移流程: +1. 尝试获取`FAILOVER_KEY`锁,确保同一时间只有一个服务实例处理故障转移。 +2. 调用`JobExecutionFailover`和`CommonTaskFailover`处理器,重新分配下线服务实例上正在运行的任务。 +3. 释放`FAILOVER_KEY`锁。 + +```mermaid +flowchart TD +A[服务实例A下线] --> B{注册中心检测} +B --> |ZooKeeper| C[ZooKeeper自动删除临时节点] +B --> |MySQL| D[ServerChecker发现update_time超时] +C --> E[通知所有订阅者] +D --> E +E --> F[Register组件收到REMOVE事件] +F --> G[尝试获取FAILOVER_KEY锁] +G --> H{获取成功?} +H --> |是| I[处理任务故障转移] +H --> |否| J[等待并重试] +I --> K[释放FAILOVER_KEY锁] +K --> L[故障转移完成] +``` + +**图示来源** +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) + +**本节来源** +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L212-L244) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L88-L108) + +## 服务注销与资源清理 +服务的正常注销和异常关闭时的资源清理是保证系统稳定的重要环节。 + +### 正常注销流程 +当服务正常关闭时,`Register`组件的`close()`方法会被调用,进而调用`Registry`的`close()`方法。 +- **ZooKeeper**:`ZooKeeperRegistry`的`close()`方法会关闭`CuratorFramework`客户端和所有`TreeCache`,ZooKeeper会自动删除该客户端创建的所有临时节点。 +- **MySQL**:`MysqlRegistry`的`close()`方法会依次调用`MysqlMutex`和`MysqlServerStateManager`的`close()`方法。`MysqlServerStateManager`会执行`unRegistry()`,从`dv_server`表中删除本服务实例的记录。 + +### 异常关闭处理 +- **ZooKeeper**:由于使用了临时节点,服务异常关闭后,ZooKeeper会在会话超时后自动清理其注册信息,无需额外处理。 +- **MySQL**:服务异常关闭时,无法执行`unRegistry()`。此时依赖`ServerChecker`定时任务来发现超时的服务实例,并将其从`dv_server`表中清理。 + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L208-L211) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L102-L105) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L69-L71) + +## 服务注册时序图 +以下时序图详细展示了DataVines服务启动时,客户端与注册中心的完整交互过程。 + +```mermaid +sequenceDiagram +participant Server as DataVines服务 +participant Register as Register组件 +participant RegistryHolder as RegistryHolder +participant Registry as Registry接口 +participant Impl as 具体实现(ZK/MySQL) +participant Storage as 存储(ZooKeeper/MySQL) +Server->>Register : start() +Register->>Register : updateCommonProperties() +Register->>RegistryHolder : getRegistry() +alt 首次初始化 +RegistryHolder->>RegistryHolder : 根据registry.type创建实例 +RegistryHolder->>Impl : new 实例() +RegistryHolder->>Impl : init(properties) +Impl->>Storage : 建立连接 +RegistryHolder-->>Register : 返回Registry实例 +else 已初始化 +RegistryHolder-->>Register : 返回现有Registry实例 +end +Register->>Impl : subscribe("", listener) +Impl->>Storage : 设置监听器 +Register->>Impl : getActiveServerList() +Impl->>Storage : 查询活跃服务列表 +Storage-->>Impl : 返回服务列表 +Impl-->>Register : 返回服务列表 +Register->>Register : updateServerListInfo() +Register->>Register : blockUtilAcquireLock(FAILOVER_KEY) +Register->>Register : 处理可能的故障转移 +Register->>Register : release(FAILOVER_KEY) +Register->>Register : updateServerListInfo() +Register-->>Server : 注册完成 +``` + +**图示来源** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) + +**本节来源** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L88-L135) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java#L29-L48) + +## 总结 +DataVines通过精心设计的`Registry`接口和SPI机制,实现了灵活的服务注册与发现功能。ZooKeeper实现利用了其分布式协调能力,提供了强一致性和自动故障检测,适用于对高可用性要求极高的场景。MySQL实现则降低了部署复杂度,通过定时心跳和状态检查来维护服务列表,适用于资源受限或已有MySQL基础设施的环境。两种实现都通过`Register`组件与核心业务逻辑解耦,确保了服务治理机制的稳定性和可维护性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213.md" new file mode 100644 index 00000000..be5a52d2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213/\347\263\273\347\273\237\345\220\257\345\212\250\346\265\201\347\250\213.md" @@ -0,0 +1,418 @@ +# 系统启动流程 + + +**本文引用的文件列表** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [Registry.java](file://datavines-registry/registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [SpringApplicationContext.java](file://datavines-server/src/main/java/io/datavines/server/utils/SpringApplicationContext.java) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [MysqlServerStateManager.java](file://datavines-registry/registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录:启动时序图](#附录启动时序图) + +## 引言 +本文件围绕 DataVines 的系统启动流程进行深入解析,自 DataVinesServer 主类的 main 方法出发,逐步阐述 Spring 应用上下文初始化过程(配置文件加载、Bean 注入、AOP 代理创建)、服务注册与发现机制(Registry 接口及 ZooKeeper/MySQL 注册中心自动注册)、定时任务调度器(Quartz)初始化与心跳检测线程启动,以及 TokenManager 初始化与安全配置加载顺序。同时提供启动时序图,标注关键步骤的时间节点与依赖关系,帮助开发者快速定位启动过程中的关键检查点。 + +## 项目结构 +DataVines 采用多模块分层组织,Server 启动入口位于 datavines-server 模块,核心业务与工具分布在 datavines-core、datavines-common、datavines-registry 等模块。启动流程的关键路径如下: +- 入口类:DataVinesServer +- 配置文件:application.yaml +- 安全与 AOP:TokenManager、RefreshTokenAop +- 注册与发现:Registry 接口、Register 实现、RegistryHolder +- 调度与心跳:CommonTaskScheduler、Quartz(由 application.yaml 配置)、MysqlServerStateManager 心跳线程 +- 属性与上下文:CommonPropertyUtils、SpringApplicationContext + +```mermaid +graph TB +A["DataVinesServer.main()"] --> B["SpringApplication.run(...)"] +B --> C["Spring Boot 自动装配
加载 application.yaml"] +C --> D["Bean 注入与生命周期回调
@PostConstruct"] +D --> E["初始化通用属性
initCommonProperties()"] +D --> F["启动作业执行管理器
JobExecuteManager.start()"] +D --> G["启动通用任务管理器
CommonTaskManager.start()"] +D --> H["创建失败转移组件
CommonTaskFailover / JobExecutionFailover"] +D --> I["选择注册中心插件
PluginLoader.getPluginLoader(Registry)"] +I --> J["Registry.init(props)"] +J --> K["Register.start()"] +K --> L["订阅事件/故障转移
subscribe()/failover()"] +K --> M["计算槽位与服务器列表
updateServerListInfo()"] +D --> N["启动作业调度器
JobScheduler.start()"] +D --> O["启动通用任务调度器
CommonTaskScheduler.start()"] +O --> P["心跳线程MySQL 注册中心
MysqlServerStateManager.HeartBeater"] +``` + +图表来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L63) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L88-L135) +- [MysqlServerStateManager.java](file://datavines-registry/registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L50-L54) + +章节来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L63) + +## 核心组件 +- DataVinesServer:Spring Boot 启动入口,负责应用上下文初始化、通用属性初始化、服务组件启动与优雅关闭。 +- Registry 接口与实现:抽象注册中心能力,支持 ZooKeeper 或 MySQL 等后端;Register 封装注册、订阅、槽位分配与故障转移。 +- Quartz:基于 JDBC 的集群化调度配置,由 application.yaml 驱动。 +- TokenManager 与 RefreshTokenAop:提供 JWT 签发与刷新,配合 AOP 对加注解的控制器返回结果统一刷新令牌。 +- SpringApplicationContext:静态持有 ApplicationContext,便于非 Spring 管理对象获取 Bean。 +- CommonPropertyUtils:全局属性读取与覆盖,用于注册中心类型、端口等关键参数。 + +章节来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [Registry.java](file://datavines-registry/registry-api/src/main/java/io/datavines/registry/api/Registry.java#L25-L43) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L70-L135) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L39-L63) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L38-L110) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java#L35-L59) +- [SpringApplicationContext.java](file://datavines-server/src/main/java/io/datavines/server/utils/SpringApplicationContext.java#L25-L45) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java#L109-L130) + +## 架构总览 +DataVines 启动阶段的核心交互如下: +- Spring Boot 启动后加载 application.yaml,完成数据源、Quartz、端口等基础配置。 +- DataVinesServer 在 @PostConstruct 中完成通用属性初始化、组件启动与注册中心初始化。 +- 注册中心根据配置选择 ZooKeeper 或 MySQL 插件,建立连接并启动心跳线程。 +- Register 订阅事件,触发故障转移,并维护当前服务器在活跃列表中的槽位信息。 +- Quartz 由 Spring Boot 自动装配,使用 JDBC 存储任务元数据,支持集群模式。 +- TokenManager 作为 Spring 组件被 AOP 切面注入,用于生成与刷新令牌。 + +```mermaid +graph TB +subgraph "启动阶段" +S1["SpringApplication.run()"] --> S2["加载 application.yaml"] +S2 --> S3["@PostConstruct 初始化"] +end +subgraph "注册与发现" +R1["PluginLoader.getPluginLoader(Registry)"] --> R2["Registry.init(props)"] +R2 --> R3["Register.start()"] +R3 --> R4["subscribe()/failover()"] +R3 --> R5["updateServerListInfo()"] +end +subgraph "调度与心跳" +Q1["application.yaml quartz 配置"] --> Q2["Quartz Scheduler"] +H1["MysqlServerStateManager.HeartBeater"] --> H2["周期性心跳更新"] +end +subgraph "安全与上下文" +T1["TokenManager"] --> T2["RefreshTokenAop"] +C1["SpringApplicationContext"] --> C2["静态持有 ApplicationContext"] +end +S3 --> R1 +S3 --> Q1 +S3 --> T1 +S3 --> C1 +``` + +图表来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L39-L63) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L88-L135) +- [MysqlServerStateManager.java](file://datavines-registry/registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L50-L54) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L38-L110) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java#L35-L59) +- [SpringApplicationContext.java](file://datavines-server/src/main/java/io/datavines/server/utils/SpringApplicationContext.java#L25-L45) + +## 详细组件分析 + +### DataVinesServer 启动流程与关键步骤 +- main 方法:设置线程名并调用 SpringApplication.run,进入 Spring Boot 启动序列。 +- @PostConstruct initializeAndStart: + - 初始化通用属性:从 Spring 上下文获取默认数据源,填充 CommonPropertyUtils,修正注册中心类型为 MySQL 或 PostgreSQL。 + - 启动 JobExecuteManager 与 JobExecutionResponseProcessor。 + - 启动 CommonTaskManager 与 CommonTaskFailover。 + - 通过 PluginLoader 获取 Registry 插件并初始化,随后创建 Register 并启动。 + - 启动 JobScheduler 与 CommonTaskScheduler。 + - 注册 JVM 关闭钩子,优雅关闭时依次释放资源。 + +```mermaid +sequenceDiagram +participant Main as "DataVinesServer.main()" +participant Spring as "SpringApplication.run()" +participant Post as "@PostConstruct initializeAndStart()" +participant Cfg as "initCommonProperties()" +participant Reg as "Registry(PluginLoader)" +participant RegH as "RegistryHolder" +participant RegS as "Register.start()" +participant Sch as "JobScheduler/CommonTaskScheduler" +participant Hook as "ShutdownHook" +Main->>Spring : "启动应用" +Spring-->>Post : "容器就绪,回调 @PostConstruct" +Post->>Cfg : "读取数据源与端口,设置注册中心类型" +Post->>Reg : "PluginLoader 获取 Registry 插件并 init(props)" +Reg-->>RegH : "RegistryHolder.setRegistry(registry)" +Post->>RegS : "Register.start() 订阅/故障转移/槽位计算" +Post->>Sch : "启动作业与通用任务调度器" +Spring-->>Hook : "注册关闭钩子" +``` + +图表来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L141-L158) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L88-L135) + +章节来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L141-L158) + +### 配置文件加载与 Bean 注入 +- application.yaml: + - 数据源与 HikariCP 连接池参数。 + - Quartz 使用 JDBC 存储、集群模式、线程池大小、表前缀、检查间隔等。 + - server.port 指定服务端口。 + - logging 指向 server-logback.xml。 + - 提供 MySQL profile 下的 quartz 驱动委托类配置。 +- Bean 注入: + - DataVinesServer 持有 SpringApplicationContext、Environment、RegistryHolder。 + - SpringApplicationContext 提供静态 getBean 方法,供非 Spring 管理组件获取 Bean。 + - TokenManager 作为 Spring 组件,@Value 注入 jwt 配置。 + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [SpringApplicationContext.java](file://datavines-server/src/main/java/io/datavines/server/utils/SpringApplicationContext.java#L25-L45) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L38-L50) + +### AOP 代理创建与 TokenManager 初始化 +- TokenManager: + - 作为 Spring 组件,使用 @Value 从配置中读取 jwt.secret、timeout、algorithm。 + - 提供签发、刷新、校验与过期判断等方法。 +- RefreshTokenAop: + - 基于 @Aspect 的环绕通知,拦截加注解的控制器方法,在返回前统一刷新令牌并封装响应。 + - 通过 @Resource 注入 TokenManager。 +- AOP 代理创建: + - Spring Boot Starter AOP 已引入,结合 @EnableAspectJAutoProxy,确保切面生效。 + - TokenManager 与 RefreshTokenAop 均为 Spring Bean,由容器负责实例化与代理包装。 + +```mermaid +classDiagram +class TokenManager { ++generateToken(...) ++refreshToken(token) ++validateToken(token, username, password) ++getUsername(token) ++getPassword(token) +} +class RefreshTokenAop { ++pointCut() ++doAroundReturningAdvice(joinPoint) +} +class ResultMap { ++successAndRefreshToken(request) ++payload(result) +} +RefreshTokenAop --> TokenManager : "注入" +RefreshTokenAop --> ResultMap : "构造响应" +``` + +图表来源 +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L38-L110) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java#L35-L59) + +章节来源 +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L38-L110) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java#L35-L59) + +### 服务注册与发现机制 +- Registry 接口: + - 定义 init、acquire、release、subscribe、unSubscribe、getActiveServerList、close 等能力。 +- Register: + - 通过 PluginLoader 获取具体 Registry 实现,初始化后订阅事件。 + - 启动时尝试获取故障转移锁,执行作业与通用任务的故障转移逻辑。 + - 维护活跃服务器列表,计算当前服务器在队列中的槽位,用于任务分片。 +- RegistryHolder: + - 保存已初始化的 Registry 实例,供其他组件使用。 +- 注册中心类型选择: + - 默认值来自 common.properties;若未显式指定,DataVinesServer 会依据数据源 URL 自动推断为 mysql 或 postgresql。 + +```mermaid +flowchart TD +Start(["Register.start()"]) --> Sleep["等待短暂时间"] +Sleep --> Subscribe["registry.subscribe() 订阅事件"] +Subscribe --> Failover["获取故障转移锁并执行 failover()"] +Failover --> Active["查询活跃服务器列表"] +Active --> Queue["更新优先队列与槽位映射"] +Queue --> Slot["计算 currentSlot/totalSlot"] +Slot --> End(["完成启动"]) +``` + +图表来源 +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L88-L135) +- [Registry.java](file://datavines-registry/registry-api/src/main/java/io/datavines/registry/api/Registry.java#L25-L43) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java#L24-L36) +- [common.properties](file://datavines-common/src/main/resources/common.properties#L18-L25) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L151-L156) + +章节来源 +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L70-L135) +- [Registry.java](file://datavines-registry/registry-api/src/main/java/io/datavines/registry/api/Registry.java#L25-L43) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java#L24-L36) +- [common.properties](file://datavines-common/src/main/resources/common.properties#L18-L25) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L151-L156) + +### 定时任务调度器(Quartz)初始化 +- application.yaml 中配置了 Quartz 使用 JDBC 存储、集群模式、线程池大小、表前缀、检查间隔等。 +- Spring Boot 自动装配 Quartz Scheduler,使用本地数据源存储任务元数据。 +- 业务侧通过 QuartzExecutors 等服务添加/更新任务触发器,实现按 Cron 表达式调度。 + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L39-L63) + +### 心跳检测线程启动 +- 在 MySQL 注册中心实现中,MysqlServerStateManager 启动两个 ScheduledExecutorService: + - HeartBeater:每 2 秒更新一次心跳记录。 + - ServerChecker:每 10 秒扫描一次活跃服务器列表,检测离线节点并触发故障转移。 +- 心跳与离线检测保证了注册中心的可用性与一致性。 + +章节来源 +- [MysqlServerStateManager.java](file://datavines-registry/registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L50-L54) +- [MysqlServerStateManager.java](file://datavines-registry/registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L212-L244) + +### 调试日志与断点建议 +- 关键日志位置: + - DataVinesServer.initializeAndStart() 开始与结束日志。 + - Register.updateServerListInfo() 输出活跃服务器列表与槽位信息。 + - MysqlServerStateManager.HeartBeater/ServerChecker 日志输出心跳与离线检测结果。 +- 断点建议: + - DataVinesServer.main() 入口处。 + - DataVinesServer.initializeAndStart() 内部各组件初始化处。 + - Register.start() 订阅事件处理分支。 + - MysqlServerStateManager.registry() 初始化与心跳循环。 + +章节来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L74-L110) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L163-L192) +- [MysqlServerStateManager.java](file://datavines-registry/registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L212-L244) + +## 依赖关系分析 +- 组件耦合与内聚: + - DataVinesServer 与 Spring 上下文强耦合,但通过 SpringApplicationContext 降低直接依赖。 + - Register 依赖 Registry 接口与 ConfigService,通过 SPI 插件化实现注册中心可替换。 + - TokenManager 与 RefreshTokenAop 通过 Spring 注入,形成横切关注点。 +- 外部依赖: + - Quartz 由 application.yaml 驱动,使用 JDBC 存储。 + - 注册中心可选 ZooKeeper 或 MySQL,通过 PluginLoader 动态加载。 +- 循环依赖风险: + - 当前结构未见明显循环依赖;Register 与 ConfigService 通过 Spring 解耦。 + +```mermaid +graph LR +DV["DataVinesServer"] --> SA["SpringApplicationContext"] +DV --> RH["RegistryHolder"] +DV --> REG["Registry(PluginLoader)"] +REG --> RGI["Registry 接口"] +REG --> RST["Register"] +RST --> CFG["ConfigService"] +DV --> SCH["JobScheduler/CommonTaskScheduler"] +DV --> TOK["TokenManager"] +TOK --> AOP["RefreshTokenAop"] +DV --> QZ["Quartz Scheduler"] +``` + +图表来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L70-L135) +- [Registry.java](file://datavines-registry/registry-api/src/main/java/io/datavines/registry/api/Registry.java#L25-L43) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L38-L110) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java#L35-L59) + +章节来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L70-L135) +- [Registry.java](file://datavines-registry/registry-api/src/main/java/io/datavines/registry/api/Registry.java#L25-L43) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L38-L110) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java#L35-L59) + +## 性能考量 +- 线程池与并发: + - Quartz 线程池大小与守护线程设置需结合业务负载调整。 + - Register 与 CommonTaskScheduler 使用固定退避策略与睡眠间隔,避免过度轮询。 +- 资源释放: + - 优雅关闭时依次释放 JobExecuteManager、Register、Failover 与数据源,防止资源泄漏。 +- 注册中心性能: + - MySQL 注册中心的心跳与检查间隔可按集群规模与网络延迟调优。 + +[本节为通用指导,无需列出章节来源] + +## 故障排查指南 +- 启动失败排查: + - 检查 application.yaml 中数据库连接、Quartz 配置是否正确。 + - 确认 common.properties 中 registry.type 与注册中心地址配置。 +- 注册中心问题: + - 查看 MysqlServerStateManager 心跳与离线检测日志,确认心跳更新与活跃列表是否正常。 + - 若使用 ZooKeeper,确认 ZK 地址与权限配置。 +- 调度异常: + - 检查 Quartz 表前缀与驱动委托类配置,确保 schema 初始化策略符合预期。 +- 安全相关: + - 确认 TokenManager 的 jwt.secret、timeout、algorithm 配置是否一致。 + - 检查 RefreshTokenAop 是否生效,控制器返回体是否包含刷新后的令牌。 + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [common.properties](file://datavines-common/src/main/resources/common.properties#L18-L25) +- [MysqlServerStateManager.java](file://datavines-registry/registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L212-L244) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L38-L110) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java#L35-L59) + +## 结论 +DataVines 的启动流程以 Spring Boot 为基础,通过 @PostConstruct 完成通用属性初始化与核心组件启动,注册中心采用 SPI 插件化设计,支持 ZooKeeper 与 MySQL。Quartz 基于 JDBC 的集群化配置保障任务可靠性,心跳线程确保注册中心健康状态。TokenManager 与 RefreshTokenAop 提供统一的安全响应封装。整体流程清晰、职责分离明确,便于扩展与维护。 + +[本节为总结性内容,无需列出章节来源] + +## 附录:启动时序图 +以下时序图标注了关键步骤的时间节点与依赖关系,帮助开发者理解启动过程中的关键检查点。 + +```mermaid +sequenceDiagram +participant Dev as "开发者" +participant Main as "DataVinesServer.main()" +participant Boot as "SpringApplication.run()" +participant Ctx as "Spring 上下文" +participant Init as "initializeAndStart()" +participant Cfg as "initCommonProperties()" +participant DS as "DataSource(Hikari)" +participant Env as "Environment" +participant Reg as "Registry(PluginLoader)" +participant RegH as "RegistryHolder" +participant RegS as "Register.start()" +participant Sch as "JobScheduler/CommonTaskScheduler" +participant Hook as "ShutdownHook" +Dev->>Main : "启动进程" +Main->>Boot : "运行应用" +Boot->>Ctx : "加载 application.yaml" +Ctx-->>Init : "回调 @PostConstruct" +Init->>Cfg : "读取数据源与端口" +Cfg->>DS : "获取默认数据源" +Cfg->>Env : "读取 server.port" +Init->>Reg : "选择注册中心插件并 init(props)" +Reg-->>RegH : "RegistryHolder.setRegistry(registry)" +Init->>RegS : "Register.start() 订阅/故障转移/槽位计算" +Init->>Sch : "启动作业与通用任务调度器" +Boot-->>Hook : "注册关闭钩子" +Hook->>Sch : "优雅关闭" +Hook->>RegS : "释放资源" +Hook->>RegH : "关闭注册中心" +``` + +图表来源 +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L141-L158) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L88-L135) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\344\273\273\345\212\241\345\217\202\346\225\260\346\236\204\345\273\272.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\344\273\273\345\212\241\345\217\202\346\225\260\346\236\204\345\273\272.md" new file mode 100644 index 00000000..fe9eb1c3 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\344\273\273\345\212\241\345\217\202\346\225\260\346\236\204\345\273\272.md" @@ -0,0 +1,216 @@ +# 任务参数构建 + + +**本文档引用的文件** +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java) +- [DataReconciliationJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataReconciliationJobParameter.java) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) +- [DataQualityJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataQualityJobParameter.java) +- [DataProfileJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataProfileJobParameter.java) +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [JobType.java](file://datavines-common/src/main/java/io/datavines/common/enums/JobType.java) +- [Configurations.java](file://datavines-common/src/main/java/io/datavines/common/config/Configurations.java) +- [ConfigChecker.java](file://datavines-common/src/main/java/io/datavines/common/config/ConfigChecker.java) +- [JobParameterUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/JobParameterUtils.java) + + +## 目录 +1. [任务参数构建机制概述](#任务参数构建机制概述) +2. [JobExecutionParameterBuilderFactory工厂模式分析](#jobexecutionparameterbuilderfactory工厂模式分析) +3. [BaseJobParameter基类设计解析](#basejobparameter基类设计解析) +4. [DataQualityJobParameter与DataReconciliationJobParameter结构差异](#dataqualityjobparameter与datareconciliationjobparameter结构差异) +5. [参数对象组装过程详解](#参数对象组装过程详解) +6. [Configurations配置容器作用](#configurations配置容器作用) +7. [参数验证流程与默认值填充机制](#参数验证流程与默认值填充机制) + +## 任务参数构建机制概述 + +DataVines中的任务参数构建机制采用工厂模式和建造者模式相结合的设计,通过`JobExecutionParameterBuilderFactory`根据不同的`JobType`创建相应的参数构建器。该机制的核心目标是根据不同类型的任务(数据质量检查、数据概览检查、数据比对检查)构建出符合要求的执行参数对象。参数构建过程涉及数据源配置、检查规则配置、预期值配置等核心字段的填充,最终生成可用于任务执行的`JobExecutionParameter`对象。 + +**本节来源** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java) + +## JobExecutionParameterBuilderFactory工厂模式分析 + +`JobExecutionParameterBuilderFactory`是任务参数构建器的工厂类,采用静态工厂方法模式根据`JobType`枚举值返回相应的`ParameterBuilder`实现。该工厂类通过switch语句判断任务类型,为不同类型的任务返回不同的构建器实例: + +- `DATA_QUALITY`和`DATA_PROFILE`类型返回`DataQualityJobParameterBuilder`实例 +- `DATA_RECONCILIATION`类型返回`DataReconciliationJobParameterBuilder`实例 +- 默认情况下返回`DataQualityJobParameterBuilder`实例 + +这种设计实现了构建器的解耦,使得新增任务类型时只需添加相应的构建器实现,而无需修改工厂类的核心逻辑,符合开闭原则。 + +```mermaid +classDiagram +class JobExecutionParameterBuilderFactory { ++static ParameterBuilder builder(JobType jobType) +} +class ParameterBuilder { +<> ++String buildJobExecutionParameter(String jobParameter, ConnectionInfo srcConnectionInfo, ConnectionInfo targetConnectionInfo) +} +class DataQualityJobParameterBuilder { ++String buildJobExecutionParameter(String jobParameter, ConnectionInfo srcConnectionInfo, ConnectionInfo targetConnectionInfo) +} +class DataReconciliationJobParameterBuilder { ++String buildJobExecutionParameter(String jobParameter, ConnectionInfo connectionInfo, ConnectionInfo connectionInfo2) +} +JobExecutionParameterBuilderFactory --> ParameterBuilder : "creates" +DataQualityJobParameterBuilder --> ParameterBuilder : "implements" +DataReconciliationJobParameterBuilder --> ParameterBuilder : "implements" +``` + +**图表来源** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java) + +**本节来源** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java) + +## BaseJobParameter基类设计解析 + +`BaseJobParameter`作为所有任务参数的基类,采用继承方式为具体任务参数类提供统一的基础属性。该基类的设计意图是提取不同类型任务参数的共性字段,实现代码复用和结构统一。基类中定义了以下核心字段: + +- `metricType`: 指标类型,标识具体的检查指标 +- `metricParameter`: 指标参数,包含检查规则的具体配置 +- `expectedType`: 预期值类型,默认为"table_total_rows" +- `expectedParameter`: 预期值参数,定义预期值的计算方式 +- `resultFormula`: 结果计算公式,默认为"percentage" +- `operator`: 比较操作符,默认为"gt"(大于) +- `threshold`: 阈值,默认为0 + +通过继承`BaseJobParameter`,具体任务参数类可以复用这些基础字段,同时根据自身需求扩展特定的属性,实现了良好的扩展性和维护性。 + +```mermaid +classDiagram +class BaseJobParameter { +-String metricType +-Map metricParameter +-String expectedType +-Map expectedParameter +-String resultFormula +-String operator +-double threshold +} +class DataQualityJobParameter { +} +class DataProfileJobParameter { +} +class DataReconciliationJobParameter { +-String metricType +-Map metricParameter2 +-List mappingColumns +} +BaseJobParameter <|-- DataQualityJobParameter +BaseJobParameter <|-- DataProfileJobParameter +BaseJobParameter <|-- DataReconciliationJobParameter +``` + +**图表来源** +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [DataQualityJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataQualityJobParameter.java) +- [DataProfileJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataProfileJobParameter.java) +- [DataReconciliationJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataReconciliationJobParameter.java) + +**本节来源** +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) + +## DataQualityJobParameter与DataReconciliationJobParameter结构差异 + +`DataQualityJobParameter`和`DataReconciliationJobParameter`虽然都继承自`BaseJobParameter`,但它们在结构和用途上有显著差异: + +`DataQualityJobParameter`是一个简单的继承类,没有添加任何额外字段,主要用途是作为数据质量检查任务的参数容器,直接使用基类中定义的所有字段来配置检查规则。 + +相比之下,`DataReconciliationJobParameter`针对数据比对场景进行了专门扩展,添加了以下特有字段: +- `metricType`: 覆盖基类字段,默认设置为"multi_table_accuracy" +- `metricParameter2`: 额外的指标参数映射,用于存储比对任务特有的配置 +- `mappingColumns`: 列映射列表,定义源表和目标表之间的列对应关系 + +这种设计差异反映了两种任务类型的不同需求:数据质量检查主要关注单表或单数据源的指标计算,而数据比对需要处理两个数据源之间的映射关系和比对逻辑。 + +**本节来源** +- [DataQualityJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataQualityJobParameter.java) +- [DataReconciliationJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataReconciliationJobParameter.java) + +## 参数对象组装过程详解 + +任务参数对象的组装过程由具体的`ParameterBuilder`实现类完成,主要步骤包括: + +1. **参数解析**:使用`JSONUtils.toList()`将JSON格式的参数字符串解析为相应的参数对象列表 +2. **连接信息处理**:从`ConnectionInfo`对象中提取数据源配置,构建`ConnectorParameter` +3. **参数合并**:对于数据比对任务,将`metricParameter`和`metricParameter2`进行合并 +4. **特殊字段处理**:将`mappingColumns`列表转换为JSON字符串并放入指标参数中 +5. **结果构建**:创建`JobExecutionParameter`对象,设置指标参数列表和连接器参数 +6. **序列化输出**:将构建完成的参数对象转换为JSON字符串返回 + +以`DataReconciliationJobParameterBuilder`为例,其组装过程特别处理了`mappingColumns`字段,将其序列化后放入`metricParameter`中,确保列映射信息能够正确传递到执行层。 + +```mermaid +flowchart TD +Start([开始]) --> ParseParameter["解析参数JSON"] +ParseParameter --> CheckNotEmpty{"参数列表非空?"} +CheckNotEmpty --> |否| ReturnNull["返回null"] +CheckNotEmpty --> |是| CreateJobExecutionParameter["创建JobExecutionParameter对象"] +CreateJobExecutionParameter --> ProcessMetricParameter["处理指标参数"] +ProcessMetricParameter --> MergeParameters["合并metricParameter和metricParameter2"] +MergeParameters --> HandleMappingColumns["处理mappingColumns"] +HandleMappingColumns --> SerializeMappingColumns["将mappingColumns序列化为JSON"] +SerializeMappingColumns --> SetToMetricParameter["放入metricParameter"] +SetToMetricParameter --> SetMetricParameterList["设置metricParameterList"] +SetMetricParameterList --> BuildConnectorParameter["构建连接器参数"] +BuildConnectorParameter --> SetConnectorParameter["设置connectorParameter"] +SetConnectorParameter --> SerializeResult["序列化结果为JSON"] +SerializeResult --> ReturnResult["返回JSON字符串"] +ReturnNull --> End([结束]) +ReturnResult --> End +``` + +**图表来源** +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) + +**本节来源** +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) + +## Configurations配置容器作用 + +`Configurations`类作为配置容器,提供了统一的配置管理接口。该类封装了`Properties`对象,提供了一系列便捷的方法来获取配置值: + +- `getString(String key)`: 根据键获取字符串值 +- `getString(String key, String defaultValue)`: 根据键获取字符串值,如果不存在则返回默认值 + +`Configurations`的作用主要体现在: +1. **配置抽象**:将底层的`Properties`实现细节封装起来,提供更友好的API +2. **类型安全**:通过方法重载提供默认值支持,避免空指针异常 +3. **扩展性**:为未来添加其他类型的配置获取方法(如getInt、getBoolean等)提供了基础 + +该配置容器在参数构建过程中被广泛使用,用于获取各种配置项,确保参数构建的灵活性和可配置性。 + +**本节来源** +- [Configurations.java](file://datavines-common/src/main/java/io/datavines/common/config/Configurations.java) + +## 参数验证流程与默认值填充机制 + +DataVines的参数验证流程和默认值填充机制确保了任务参数的完整性和有效性。验证流程主要通过`ConfigChecker`类实现,其核心方法`checkConfig`接受配置映射和必需选项集合,检查所有必需选项是否存在: + +- 如果存在缺失的必需选项,返回验证失败结果,并提供详细的错误信息 +- 如果所有必需选项都存在,返回验证成功结果 + +默认值填充机制主要体现在以下几个方面: +1. **基类字段默认值**:`BaseJobParameter`中的`expectedType`、`resultFormula`、`operator`和`threshold`都设置了默认值 +2. **工厂类默认行为**:`JobExecutionParameterBuilderFactory`为未知任务类型提供默认的构建器 +3. **配置获取默认值**:`Configurations.getString(key, defaultValue)`方法支持指定默认值 + +此外,`JobParameterUtils`工具类提供了`regenerateJobParameterList`方法,用于重新生成和规范化参数列表,进一步确保参数的正确性。这种多层次的验证和默认值机制有效防止了因参数缺失或错误导致的任务执行失败。 + +**本节来源** +- [ConfigChecker.java](file://datavines-common/src/main/java/io/datavines/common/config/ConfigChecker.java) +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [JobParameterUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/JobParameterUtils.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266.md" new file mode 100644 index 00000000..9c0e8b8d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266.md" @@ -0,0 +1,326 @@ +# 任务调度机制 + + +**本文档引用的文件** +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobParameterUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/JobParameterUtils.java) +- [CommandContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/CommandContext.java) + + +## 目录 +1. [任务调度流程概述](#任务调度流程概述) +2. [Quartz定时任务触发](#quartz定时任务触发) +3. [任务参数构建机制](#任务参数构建机制) +4. [任务参数序列化与反序列化](#任务参数序列化与反序列化) +5. [任务执行请求的创建与发送](#任务执行请求的创建与发送) +6. [任务参数差异分析](#任务参数差异分析) +7. [控制参数传递机制](#控制参数传递机制) + +## 任务调度流程概述 + +DataVines的任务调度流程从Quartz定时任务触发开始,经过任务参数构建、序列化、执行请求创建等环节,最终将任务发送到Engine模块执行。整个流程涉及多个核心组件的协同工作,包括调度器、参数构建器、执行管理器等。 + +```mermaid +flowchart TD +A[Quartz定时任务] --> B[DataQualityScheduleJob] +B --> C[JobExternalService] +C --> D[JobExecuteManager] +D --> E[JobExecutionParameterBuilderFactory] +E --> F[ParameterBuilder] +F --> G[JobExecutionParameter] +G --> H[JobExecutionRequest] +H --> I[Engine模块] +``` + +**图表来源** +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) + +## Quartz定时任务触发 + +DataVines使用Quartz作为任务调度框架,当定时任务触发时,`DataQualityScheduleJob`类的`execute`方法会被调用。该方法从JobDataMap中获取jobId,然后通过`JobExternalService`获取具体的Job信息并执行。 + +```mermaid +sequenceDiagram +participant Quartz as Quartz调度器 +participant Job as DataQualityScheduleJob +participant Service as JobExternalService +participant Manager as JobExecuteManager +Quartz->>Job : 触发execute方法 +Job->>Job : 从JobDataMap获取jobId +Job->>Service : getJobById(jobId) +Service-->>Job : 返回Job对象 +Job->>Service : execute(jobId, scheduleTime) +Service->>Manager : addExecuteCommand +Manager-->>Quartz : 任务执行完成 +``` + +**图表来源** +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) + +**本节来源** +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java#L54-L72) + +## 任务参数构建机制 + +任务参数的构建由`JobExecutionParameterBuilderFactory`工厂类负责,该工厂根据不同的任务类型创建相应的参数构建器。对于数据质量检查任务,使用`DataQualityJobParameterBuilder`;对于数据对账任务,使用`DataReconciliationJobParameterBuilder`。 + +```mermaid +classDiagram +class JobExecutionParameterBuilderFactory { ++builder(JobType jobType) ParameterBuilder +} +class ParameterBuilder { +<> ++buildJobExecutionParameter(String jobParameter, ConnectionInfo srcConnectionInfo, ConnectionInfo targetConnectionInfo) String +} +class DataQualityJobParameterBuilder { ++buildJobExecutionParameter(String jobParameter, ConnectionInfo srcConnectionInfo, ConnectionInfo targetConnectionInfo) String +} +class DataReconciliationJobParameterBuilder { ++buildJobExecutionParameter(String jobParameter, ConnectionInfo srcConnectionInfo, ConnectionInfo targetConnectionInfo) String +} +JobExecutionParameterBuilderFactory --> ParameterBuilder : "创建" +ParameterBuilder <|-- DataQualityJobParameterBuilder : "实现" +ParameterBuilder <|-- DataReconciliationJobParameterBuilder : "实现" +``` + +**图表来源** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) + +**本节来源** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java#L21-L34) + +## 任务参数序列化与反序列化 + +任务参数的序列化与反序列化是DataVines任务调度的核心环节。系统使用JSON格式进行数据封装,通过`JSONUtils`工具类实现对象与JSON字符串之间的转换。 + +### BaseJobParameter继承体系 + +`BaseJobParameter`是所有任务参数的基类,定义了通用的参数字段。具体的任务类型通过继承`BaseJobParameter`来扩展特定的参数。 + +```mermaid +classDiagram +class BaseJobParameter { +-String metricType +-Map metricParameter +-String expectedType +-Map expectedParameter +-String resultFormula +-String operator +-double threshold +} +class DataQualityJobParameter { +} +class DataProfileJobParameter { +} +class DataReconciliationJobParameter { +-Map metricParameter2 +-List mappingColumns +} +BaseJobParameter <|-- DataQualityJobParameter : "继承" +BaseJobParameter <|-- DataProfileJobParameter : "继承" +BaseJobParameter <|-- DataReconciliationJobParameter : "继承" +``` + +**图表来源** +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [DataReconciliationJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataReconciliationJobParameter.java) + +**本节来源** +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java#L26-L41) + +### JSON格式数据封装 + +任务参数在传输过程中被序列化为JSON字符串。`JobExecutionParameter`类包含连接器参数和指标参数列表,这些对象通过`JSONUtils.toJsonString`方法转换为JSON格式。 + +```mermaid +flowchart TD +A[BaseJobParameter列表] --> B[JobExecutionParameter] +B --> C[JSONUtils.toJsonString] +C --> D[JSON字符串] +D --> E[网络传输] +E --> F[JSONUtils.parseObject] +F --> G[JobExecutionParameter对象] +G --> H[BaseJobParameter列表] +``` + +**图表来源** +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) + +## 任务执行请求的创建与发送 + +任务执行请求的创建和发送由`JobExecuteManager`负责。该管理器接收执行命令,创建`JobExecutionRequest`对象,并通过HTTP客户端将其发送到Engine模块。 + +### Command命令创建 + +当任务需要执行时,系统会创建一个`CommandContext`对象,其中包含命令码、任务执行ID和任务执行请求。 + +```mermaid +classDiagram +class CommandContext { +-CommandCode commandCode +-Long jobExecutionId +-JobExecutionRequest jobExecutionRequest +} +class CommandCode { +JOB_EXECUTE_REQUEST +JOB_KILL_REQUEST +JOB_EXECUTE_ACK +JOB_EXECUTE_RESPONSE +} +class JobExecutionRequest { +-long jobExecutionId +-String executePlatformType +-String engineType +-String applicationParameter +-Integer retryTimes +-Integer timeout +-TimeoutStrategy timeoutStrategy +} +CommandContext --> CommandCode : "包含" +CommandContext --> JobExecutionRequest : "包含" +``` + +**图表来源** +- [CommandContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/CommandContext.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) + +**本节来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L542-L553) + +### 执行请求发送流程 + +`JobExecuteManager`中的`JobExecutionExecutor`线程负责处理执行命令队列中的命令,将任务执行请求发送到Engine模块。 + +```mermaid +sequenceDiagram +participant Manager as JobExecuteManager +participant Executor as JobExecutionExecutor +participant Runner as JobRunner +participant Engine as Engine模块 +Manager->>Manager : addExecuteCommand +Manager->>Executor : 将CommandContext放入队列 +loop 处理命令 +Executor->>Executor : 从队列获取CommandContext +Executor->>Executor : 根据CommandCode处理 +Executor->>Runner : executeJobExecution +Runner->>Runner : 创建JobRunner +Runner->>Engine : 通过HTTP客户端发送请求 +Engine-->>Runner : 返回响应 +Runner-->>Executor : 处理响应 +end +``` + +**图表来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobRunner.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/runner/JobRunner.java) + +## 任务参数差异分析 + +不同类型的检查任务在参数结构上存在显著差异,主要体现在`metricParameter`字段的内容上。 + +### 单表质量检查任务参数 + +单表质量检查任务的参数主要关注单个表的指标计算,如行数、空值率等。 + +```json +{ + "metricType": "table_row_count", + "metricParameter": { + "database": "test_db", + "table": "user_info", + "column": "*" + }, + "expectedType": "fix", + "expectedParameter": { + "value": "1000" + }, + "resultFormula": "percentage", + "operator": "gt", + "threshold": 0.95 +} +``` + +### 跨表准确性检查任务参数 + +跨表准确性检查任务需要比较两个表的数据,因此参数中包含两个数据源的连接信息和字段映射关系。 + +```json +{ + "metricType": "multi_table_accuracy", + "metricParameter": { + "database": "source_db", + "table": "user_info", + "column": "id" + }, + "metricParameter2": { + "database": "target_db", + "table": "user_info_copy", + "column": "id" + }, + "mappingColumns": [ + { + "sourceColumn": "id", + "targetColumn": "id" + }, + { + "sourceColumn": "name", + "targetColumn": "name" + } + ], + "expectedType": "table_total_rows", + "resultFormula": "diff_percentage", + "operator": "lt", + "threshold": 0.01 +} +``` + +**本节来源** +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java#L33-L56) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java#L31-L57) + +## 控制参数传递机制 + +任务调度过程中,优先级、超时策略等控制参数通过`JobExecutionRequest`对象进行传递。 + +### 优先级与重试机制 + +系统通过`retryTimes`和`retryInterval`参数控制任务的重试行为。当任务执行失败时,如果剩余重试次数大于0,系统会自动重新提交任务。 + +```mermaid +flowchart TD +A[任务执行失败] --> B{retryTimes > 0?} +B --> |是| C[减少retryTimes] +C --> D[等待retryInterval毫秒] +D --> E[重新提交任务] +B --> |否| F[标记任务失败] +F --> G[发送失败通知] +``` + +### 超时策略 + +超时策略由`timeout`和`timeoutStrategy`参数控制。系统使用`HashedWheelTimer`来监控任务执行时间,当任务执行时间超过`timeout`时,根据`timeoutStrategy`采取相应措施。 + +```java +wheelTimer.newTimeout( + new JobExecutionTimeoutTimerTask( + jobExecutionId, jobExecutionRequest.getRetryTimes()), + jobExecutionRequest.getTimeout()+2, TimeUnit.SECONDS); +``` + +**本节来源** +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java#L60-L66) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L404-L425) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\345\221\275\344\273\244\345\210\206\345\217\221\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\345\221\275\344\273\244\345\210\206\345\217\221\346\234\272\345\210\266.md" new file mode 100644 index 00000000..d440df48 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\345\221\275\344\273\244\345\210\206\345\217\221\346\234\272\345\210\266.md" @@ -0,0 +1,263 @@ +# 命令分发机制 + + +**本文档引用的文件** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java) +- [CommandServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CommandServiceImpl.java) +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [CommandContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\CommandContext.java) +- [CommandCategory.java](file://datavines-server\src\main\java\io\datavines\server\enums\CommandCategory.java) +- [CommandType.java](file://datavines-server\src\main\java\io\datavines\server\enums\CommandType.java) +- [JobExecuteResponseCommand.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\JobExecuteResponseCommand.java) +- [Command.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\Command.java) + + +## 目录 +1. [命令分发流程概述](#命令分发流程概述) +2. [Quartz调度器触发](#quartz调度器触发) +3. [命令生成与持久化](#命令生成与持久化) +4. [任务执行上下文管理](#任务执行上下文管理) +5. [命令分类机制](#命令分类机制) +6. [执行环境信息封装](#执行环境信息封装) +7. [完整流程时序图](#完整流程时序图) + +## 命令分发流程概述 + +DataVines的命令分发机制是一个完整的任务调度与执行流程,从Quartz调度器触发定时任务开始,经过命令生成、持久化、执行管理到最终结果反馈的完整闭环。该机制确保了数据质量检查任务能够按照预定的时间计划准确执行,并提供了完善的错误处理和重试机制。 + +整个流程的核心组件包括Quartz调度器、命令服务、任务执行管理器和命令上下文等。这些组件协同工作,实现了从调度触发到任务执行的无缝衔接,为数据质量监控提供了可靠的技术保障。 + +## Quartz调度器触发 + +DataVines使用Quartz作为其核心调度引擎,负责触发数据质量检查任务的执行。当调度时间到达时,Quartz会触发`DataQualityScheduleJob`类的执行,这是整个命令分发流程的起点。 + +`DataQualityScheduleJob`实现了Quartz的Job接口,其execute方法会在调度时间到达时被调用。该方法从JobDataMap中获取任务ID,然后通过SpringApplicationContext获取JobExternalService实例,最终调用execute方法启动任务执行流程。 + +```mermaid +sequenceDiagram +participant Quartz as Quartz调度器 +participant DataQualityScheduleJob as DataQualityScheduleJob +participant JobExternalService as JobExternalService +Quartz->>DataQualityScheduleJob : 触发execute() +DataQualityScheduleJob->>DataQualityScheduleJob : 从JobDataMap获取jobId +DataQualityScheduleJob->>JobExternalService : getJobById(jobId) +JobExternalService-->>DataQualityScheduleJob : 返回Job对象 +DataQualityScheduleJob->>JobExternalService : execute(jobId, scheduleTime) +``` + +**时序图来源** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L54-L73) + +**本节来源** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L17-L75) + +## 命令生成与持久化 + +当`DataQualityScheduleJob`触发任务执行后,系统会生成一个`JobExecution`对象并将其保存到数据库中。随后,系统会创建一个`Command`对象,该对象包含了任务执行所需的所有信息,并通过`CommandService`将其持久化到数据库。 + +在`JobServiceImpl`类中,`execute`方法负责处理任务执行请求。该方法首先创建`JobExecution`对象并保存,然后创建`Command`对象,设置其类型为`CommandType.START`,并将其插入到命令表中。这个命令对象将成为任务执行的指令载体。 + +```mermaid +sequenceDiagram +participant JobServiceImpl as JobServiceImpl +participant JobExecutionService as JobExecutionService +participant CommandService as CommandService +participant Database as 数据库 +JobServiceImpl->>JobExecutionService : 保存JobExecution +JobExecutionService->>Database : 插入JobExecution记录 +Database-->>JobExecutionService : 返回结果 +JobExecutionService-->>JobServiceImpl : 返回JobExecution +JobServiceImpl->>CommandService : 创建并插入Command +CommandService->>Database : 插入Command记录 +Database-->>CommandService : 返回结果 +CommandService-->>JobServiceImpl : 返回Command +``` + +**时序图来源** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L534-L551) +- [CommandServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CommandServiceImpl.java#L35-L39) + +**本节来源** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L534-L572) +- [CommandServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CommandServiceImpl.java#L1-L78) + +## 任务执行上下文管理 + +`JobExecuteManager`是任务执行上下文管理的核心组件,负责管理任务执行的整个生命周期。它维护了一个`LinkedBlockingQueue`队列,用于存放待处理的命令上下文,以及一个`ConcurrentHashMap`映射,用于跟踪未完成的任务执行。 + +当任务需要执行时,`JobExecuteManager`会创建一个`CommandContext`对象,设置其命令码为`JOB_EXECUTE_REQUEST`,并将其放入执行队列。后台的`JobExecutionExecutor`线程会不断从队列中取出命令上下文,并根据命令码执行相应的操作。 + +对于任务执行的响应,`JobExecuteManager`提供了`processJobExecutionExecuteResponse`方法,该方法接收`JobExecuteResponseCommand`对象,将其转换为`JobExecutionResponseContext`,并放入响应队列。后台的`JobExecutionResponseOperator`线程会处理这些响应,更新任务状态并进行相应的后续处理。 + +```mermaid +classDiagram +class JobExecuteManager { ++LinkedBlockingQueue jobExecutionQueue ++ConcurrentHashMap unFinishedJobExecutionMap ++LinkedBlockingQueue responseQueue ++ExecutorService executorService ++ExecutorService jobExecuteService ++addExecuteCommand(JobExecution) ++processJobExecutionExecuteResponse(JobExecuteResponseCommand) ++addKillCommand(Long) +} +class CommandContext { ++CommandCode commandCode ++Long jobExecutionId ++JobExecutionRequest jobExecutionRequest +} +class JobExecutionResponseContext { ++CommandCode commandCode ++JobExecutionRequest jobExecutionRequest +} +class JobExecuteResponseCommand { ++long jobExecutionId ++int status ++LocalDateTime endTime ++String applicationIds ++int processId +} +JobExecuteManager --> CommandContext : 包含 +JobExecuteManager --> JobExecutionResponseContext : 包含 +JobExecuteManager --> JobExecuteResponseCommand : 处理 +``` + +**类图来源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L73-L617) +- [CommandContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\CommandContext.java#L1-L31) +- [JobExecutionResponseContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseContext.java#L1-L40) +- [JobExecuteResponseCommand.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\JobExecuteResponseCommand.java#L1-L46) + +**本节来源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L73-L617) + +## 命令分类机制 + +DataVines通过`CommandCategory`和`CommandType`两个枚举类来实现命令的分类管理。`CommandCategory`用于区分不同类型的命令大类,目前包括数据质量任务和目录任务两类。`CommandType`则定义了具体的命令类型,如启动、停止、错误等。 + +`CommandCategory`枚举包含`DATA_QUALITY`和`CATALOG`两个值,分别对应代码0和1,用于区分数据质量检查任务和元数据目录任务。每个类别都有相应的描述信息,便于理解和调试。 + +`CommandType`枚举则定义了更细粒度的命令类型,包括`START`(启动)、`STOP`(停止)、`ERROR`(错误)等。这些类型在命令执行过程中起到关键作用,决定了系统对命令的处理方式。 + +```mermaid +classDiagram +class CommandCategory { ++DATA_QUALITY(0, "data quality task") ++CATALOG(1, "catalog task") ++of(Integer) ++getCode() ++getDescription() +} +class CommandType { ++START(0, "start a task") ++STOP(1, "stop a task") ++ERROR(2, "task has error") ++RECOVER_TOLERANCE_FAULT(3, "recover tolerance fault task") ++RECOVER_WAITING_THREAD(4, "recover waiting thread") ++SCHEDULER(5,"scheduler") ++of(Integer) ++getCode() ++getDescription() +} +class Command { ++CommandType type ++CommandCategory category ++String parameter ++Long jobExecutionId ++String executeHost ++Priority priority ++LocalDateTime createTime ++LocalDateTime updateTime +} +Command --> CommandType : 包含 +Command --> CommandCategory : 包含 +``` + +**类图来源** +- [CommandCategory.java](file://datavines-server\src\main\java\io\datavines\server\enums\CommandCategory.java#L1-L66) +- [CommandType.java](file://datavines-server\src\main\java\io\datavines\server\enums\CommandType.java#L1-L74) +- [Command.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\Command.java#L1-L65) + +**本节来源** +- [CommandCategory.java](file://datavines-server\src\main\java\io\datavines\server\enums\CommandCategory.java#L1-L66) +- [CommandType.java](file://datavines-server\src\main\java\io\datavines\server\enums\CommandType.java#L1-L74) + +## 执行环境信息封装 + +`CommandContext`类是执行环境信息封装的核心,它将任务执行所需的所有上下文信息封装在一个对象中。该类包含三个主要属性:`commandCode`表示命令类型,`jobExecutionId`表示任务执行ID,`jobExecutionRequest`包含完整的任务执行请求信息。 + +`CommandContext`在命令分发流程中扮演着重要角色,它作为命令的载体在各个组件之间传递。当`JobScheduler`从数据库获取到启动命令后,会将其转换为`CommandContext`对象,并通过`JobExecuteManager`的`addExecuteCommand`方法将其放入执行队列。 + +`JobExecutionRequest`对象包含了任务执行的详细信息,包括执行平台类型、引擎类型、超时设置、重试次数等。这些信息在任务执行过程中被用来配置和控制任务的运行。 + +```mermaid +flowchart TD +A[调度触发] --> B[生成Command] +B --> C[持久化到数据库] +C --> D[JobScheduler获取Command] +D --> E[转换为CommandContext] +E --> F[放入执行队列] +F --> G[JobExecuteManager处理] +G --> H[执行任务] +H --> I[生成响应] +I --> J[更新任务状态] +``` + +**流程图来源** +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java#L1-L155) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L73-L617) + +**本节来源** +- [CommandContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\CommandContext.java#L1-L31) +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java#L1-L155) + +## 完整流程时序图 + +以下是DataVines命令分发流程的完整时序图,展示了从Quartz调度器触发到任务执行完成的全过程。 + +```mermaid +sequenceDiagram +participant Quartz as Quartz调度器 +participant DataQualityScheduleJob as DataQualityScheduleJob +participant JobServiceImpl as JobServiceImpl +participant CommandService as CommandService +participant JobScheduler as JobScheduler +participant JobExecuteManager as JobExecuteManager +participant JobRunner as JobRunner +Quartz->>DataQualityScheduleJob : 触发execute() +DataQualityScheduleJob->>JobServiceImpl : execute(jobId, scheduleTime) +JobServiceImpl->>JobServiceImpl : 创建JobExecution +JobServiceImpl->>CommandService : 创建START命令 +CommandService->>数据库 : 持久化命令 +数据库-->>CommandService : 确认 +CommandService-->>JobServiceImpl : 返回 +JobServiceImpl-->>DataQualityScheduleJob : 返回 +DataQualityScheduleJob-->>Quartz : 完成 +JobScheduler->>CommandService : 获取START命令 +CommandService->>数据库 : 查询命令 +数据库-->>CommandService : 返回命令 +CommandService-->>JobScheduler : 返回命令 +JobScheduler->>JobExecuteManager : addExecuteCommand() +JobExecuteManager->>JobExecuteManager : 创建CommandContext +JobExecuteManager->>jobExecutionQueue : 放入队列 +JobExecuteManager->>JobRunner : 提交任务 +JobRunner->>JobRunner : 执行任务 +JobRunner-->>JobExecuteManager : 返回结果 +JobExecuteManager->>JobExecuteManager : 更新任务状态 +``` + +**时序图来源** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L54-L73) +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L534-L572) +- [CommandServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CommandServiceImpl.java#L1-L78) +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java#L1-L155) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L73-L617) + +**本节来源** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L17-L75) +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L534-L572) +- [CommandServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CommandServiceImpl.java#L1-L78) +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java#L1-L155) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L73-L617) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\346\211\247\350\241\214\350\247\246\345\217\221\346\265\201\347\250\213.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\346\211\247\350\241\214\350\247\246\345\217\221\346\265\201\347\250\213.md" new file mode 100644 index 00000000..53241593 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\344\273\273\345\212\241\350\260\203\345\272\246\346\234\272\345\210\266/\346\211\247\350\241\214\350\247\246\345\217\221\346\265\201\347\250\213.md" @@ -0,0 +1,325 @@ +# 执行触发流程 + + +**本文档引用的文件** +- [DatavinesBaseClient.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/base/DatavinesBaseClient.java) +- [DataVinesClient.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/DataVinesClient.java) +- [DatavinesClientConfig.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/base/DatavinesClientConfig.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionResponseProcessor.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) + + +## 目录 +1. [执行触发概述](#执行触发概述) +2. [HTTP客户端配置与超时设置](#http客户端配置与超时设置) +3. [执行请求的发送流程](#执行请求的发送流程) +4. [执行请求的接收与解析](#执行请求的接收与解析) +5. [执行结果的回调处理](#执行结果的回调处理) +6. [本地与YARN集群模式的触发差异](#本地与yarn集群模式的触发差异) +7. [执行状态更新机制](#执行状态更新机制) + +## 执行触发概述 + +DataVines系统的任务执行触发流程是一个完整的端到端过程,从Server端通过DataVinesClient向Engine模块发送执行请求开始,到执行结果的回调处理和状态更新结束。该流程涉及多个核心组件的协同工作,包括HTTP客户端、执行管理器、执行器和结果处理器。 + +整个流程的核心是`JobExecutionRequest`对象,它封装了任务执行所需的所有参数和配置信息。当任务需要执行时,Server端会创建一个`JobExecutionRequest`对象,并通过HTTP客户端将其发送到相应的执行引擎。执行引擎接收到请求后,会解析请求参数,初始化执行环境,并分配必要的资源来执行任务。 + +```mermaid +sequenceDiagram +participant Server as Server端 +participant Client as DataVinesClient +participant Engine as Engine模块 +participant Executor as AbstractEngineExecutor +participant Processor as JobExecutionResponseProcessor +Server->>Client : 创建JobExecutionRequest +Client->>Engine : 发送执行请求 +Engine->>Executor : 接收并解析请求 +Executor->>Executor : 初始化执行环境 +Executor->>Executor : 分配资源并执行 +Executor->>Processor : 发送执行结果 +Processor->>Server : 处理回调并更新状态 +``` + +**图示来源** +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [DataVinesClient.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/DataVinesClient.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [JobExecutionResponseProcessor.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java) + +**本节来源** +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) + +## HTTP客户端配置与超时设置 + +DataVines系统中的HTTP客户端配置和超时设置是确保任务执行请求可靠传输的关键因素。系统通过`DatavinesClientConfig`类定义了客户端的核心配置参数,这些参数在`DatavinesBaseClient`中被读取和应用。 + +HTTP客户端的主要配置参数包括: +- **读取超时**:`datavines.client.readTimeoutMSecs`,默认值为6000毫秒 +- **连接超时**:`datavines.client.connectTimeoutMSecs`,默认值为6000毫秒 +- **重试次数**:`datavines.client.retryTimes`,默认值为1次 +- **重试间隔**:`datavines.client.sleep.betweenRetry`,默认值为1000毫秒 + +这些配置参数在`DatavinesBaseClient`的`getClient`方法中被应用,确保了HTTP客户端在各种网络条件下都能稳定工作。读取超时和连接超时的设置可以防止客户端在不可用的服务上无限期等待,而重试机制则提高了请求的可靠性。 + +```mermaid +classDiagram +class DatavinesClientConfig { ++String CLIENT_READ_TIMEOUT_MSECS ++String CLIENT_CONNECT_TIMEOUT_MESCS ++String CLIENT_RETRY_TIMES ++String CLIENT_SLEEP_BETWEEN_RETRY +} +class DatavinesBaseClient { +-Properties configuration +-int retryTimes +-int sleepBetweenRetries ++getClient(Properties, String) Client ++callAPI(DatavinesAPI, WebResource, Object) DatavinesResponse +} +DatavinesBaseClient --> DatavinesClientConfig : "使用配置" +``` + +**图示来源** +- [DatavinesClientConfig.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/base/DatavinesClientConfig.java) +- [DatavinesBaseClient.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/base/DatavinesBaseClient.java) + +**本节来源** +- [DatavinesClientConfig.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/base/DatavinesClientConfig.java) +- [DatavinesBaseClient.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/base/DatavinesBaseClient.java) + +## 执行请求的发送流程 + +执行请求的发送流程始于Server端的`JobExecuteManager`,该组件负责管理所有待执行的任务。当一个任务需要执行时,`JobExecuteManager`会创建一个`JobExecutionRequest`对象,并将其放入待处理队列中。 + +`JobExecutionRequest`对象的创建过程包括将任务参数转换为执行参数,设置执行平台类型、引擎类型和相关配置。这个请求对象包含了任务执行所需的所有信息,包括执行平台参数、引擎参数、错误数据存储配置等。 + +一旦`JobExecutionRequest`被创建并放入队列,`DataVinesClient`就会从队列中获取请求,并通过HTTP协议将其发送到目标执行引擎。发送过程中,客户端会自动处理JSON序列化、认证头设置和响应解析等细节。 + +```mermaid +flowchart TD +Start([开始]) --> CreateRequest["创建JobExecutionRequest"] +CreateRequest --> SetParameters["设置执行参数"] +SetParameters --> ValidateRequest["验证请求参数"] +ValidateRequest --> QueueRequest["放入待处理队列"] +QueueRequest --> SendRequest["通过DataVinesClient发送"] +SendRequest --> Serialize["JSON序列化"] +Serialize --> AddAuth["添加认证头"] +AddAuth --> SendHTTP["发送HTTP请求"] +SendHTTP --> End([结束]) +``` + +**图示来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [DataVinesClient.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/DataVinesClient.java) + +**本节来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) + +## 执行请求的接收与解析 + +执行请求的接收与解析由`AbstractEngineExecutor`类及其子类负责。`AbstractEngineExecutor`是一个抽象基类,定义了执行器的基本行为和接口,所有具体的执行器都继承自这个类。 + +当执行引擎接收到`JobExecutionRequest`时,`init`方法会被调用,用于初始化执行环境。这个方法会设置日志记录器、保存请求对象,并根据请求中的参数配置执行环境。`execute`方法则负责实际的任务执行,它会根据请求中的应用参数构建执行命令并运行。 + +在初始化过程中,执行器会解析`JobExecutionRequest`中的各种参数,包括引擎参数、应用参数和执行平台参数。这些参数被用来配置具体的执行环境,如Spark或Flink的配置。执行器还会根据租户代码和任务唯一ID来设置执行上下文,确保任务在正确的环境中运行。 + +```mermaid +classDiagram +class AbstractEngineExecutor { +-JobExecutionRequest jobExecutionRequest +-Logger logger +-boolean cancel +-ProcessResult processResult ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++isCancel() boolean ++logHandle(String[]) void +} +class LocalEngineExecutor { +-LocalDataVinesBootstrap bootstrap ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void +} +class SparkEngineExecutor { +-Configurations configurations +-ShellCommandProcess shellCommandProcess ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++buildCommand() String +} +class FlinkEngineExecutor { +-Configurations configurations +-BaseCommandProcess shellCommandProcess +-boolean cancel ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++buildCommand() String +} +AbstractEngineExecutor <|-- LocalEngineExecutor +AbstractEngineExecutor <|-- SparkEngineExecutor +AbstractEngineExecutor <|-- FlinkEngineExecutor +SparkEngineExecutor --> ShellCommandProcess : "使用" +FlinkEngineExecutor --> BaseCommandProcess : "使用" +``` + +**图示来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) + +## 执行结果的回调处理 + +执行结果的回调处理由`JobExecutionResponseProcessor`组件负责。这是一个单例类,通过`getInstance`方法获取实例,确保在整个系统中只有一个处理器实例。 + +当执行引擎完成任务执行后,会通过`processJobExecutionExecuteResponse`方法将执行结果发送给处理器。处理器接收到结果后,会创建一个`JobExecutionResponseContext`对象,并将其放入响应队列中。一个后台线程会持续监听这个队列,处理每一个响应。 + +在处理响应时,处理器会根据响应中的状态码更新任务的执行状态。如果任务成功完成,状态会被更新为`SUCCESS`;如果任务失败,状态会被更新为`FAILURE`。处理器还会处理重试逻辑,根据任务的重试次数配置决定是否需要重新执行任务。 + +```mermaid +sequenceDiagram +participant Executor as 执行引擎 +participant Processor as JobExecutionResponseProcessor +participant Manager as JobExecuteManager +participant DB as 数据库 +Executor->>Processor : processJobExecutionExecuteResponse() +Processor->>Processor : 创建JobExecutionResponseContext +Processor->>Processor : 放入响应队列 +loop 监听队列 +Processor->>Processor : 从队列获取响应 +Processor->>Manager : 更新任务状态 +alt 任务成功 +Manager->>DB : 更新为SUCCESS状态 +else 任务失败 +Manager->>DB : 更新为FAILURE状态 +alt 需要重试 +Manager->>Executor : 重新提交任务 +end +end +end +``` + +**图示来源** +- [JobExecutionResponseProcessor.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) + +**本节来源** +- [JobExecutionResponseProcessor.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java) + +## 本地与YARN集群模式的触发差异 + +本地执行模式和YARN集群模式在任务触发过程中存在显著差异,这些差异主要体现在资源管理、执行环境和命令构建等方面。 + +在本地执行模式下,`LocalEngineExecutor`直接在当前JVM中执行任务。它通过创建`LocalDataVinesBootstrap`实例并调用其`execute`方法来运行任务。这种方式简单直接,适用于开发和测试环境,但无法利用集群资源。 + +而在YARN集群模式下,`SparkEngineExecutor`和`FlinkEngineExecutor`会构建复杂的命令行来提交任务到YARN集群。这些命令包括`spark-submit`或`flink`命令,以及各种配置参数。执行器还会设置YARN标签,以便于任务的跟踪和管理。 + +两种模式的主要差异体现在: +1. **资源管理**:本地模式使用本地资源,而YARN模式利用集群资源 +2. **执行环境**:本地模式在当前JVM中执行,YARN模式在集群节点上执行 +3. **命令构建**:YARN模式需要构建复杂的提交命令,本地模式则直接调用方法 +4. **容错机制**:YARN模式具有更好的容错能力,可以自动重启失败的任务 + +```mermaid +graph TD +subgraph 本地执行模式 +A[LocalEngineExecutor] +B[LocalDataVinesBootstrap] +C[当前JVM] +A --> B +B --> C +end +subgraph YARN集群模式 +D[SparkEngineExecutor] +E[SparkSubmit命令] +F[YARN集群] +G[FlinkEngineExecutor] +H[Flink命令] +D --> E +E --> F +G --> H +H --> F +end +style A fill:#f9f,stroke:#333 +style D fill:#f9f,stroke:#333 +style G fill:#f9f,stroke:#333 +``` + +**图示来源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) + +**本节来源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) + +## 执行状态更新机制 + +执行状态更新机制是DataVines系统中确保任务状态准确反映实际执行情况的核心。该机制通过`JobExecuteManager`中的`JobExecutionResponseOperator`线程实现,该线程持续监听响应队列,处理每一个执行结果。 + +当接收到执行结果时,系统会根据结果中的状态码更新任务状态。状态更新遵循`ExecutionStatus`枚举定义的状态转换规则,包括`SUBMITTED_SUCCESS`、`RUNNING_EXECUTION`、`SUCCESS`、`FAILURE`等状态。 + +对于成功完成的任务,系统会更新结束时间、应用ID和执行主机等信息,并从待处理队列中移除该任务。对于失败的任务,系统会根据配置的重试次数决定是否重新提交任务。如果重试次数用尽,任务状态将被设置为`FAILURE`。 + +系统还实现了超时处理机制,通过`JobExecutionTimeoutTimerTask`定时器任务监控长时间未完成的任务。如果任务执行时间超过预设的超时时间,系统会自动将其状态更新为`KILL`。 + +```mermaid +stateDiagram-v2 +[*] --> 待提交 +待提交 --> 已提交 : 提交成功 +已提交 --> 执行中 : 开始执行 +执行中 --> 成功 : 执行完成 +执行中 --> 失败 : 执行失败 +执行中 --> 超时 : 超时未完成 +失败 --> 重试 : 重试次数>0 +重试 --> 执行中 +超时 --> 终止 +失败 --> 终止 : 重试次数=0 +成功 --> [*] +终止 --> [*] +note right of 执行中 +监控执行进度 +更新日志和状态 +end note +note left of 失败 +记录错误信息 +触发重试逻辑 +end note +``` + +**图示来源** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionTimeoutTimerTask.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) + +**本节来源** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\345\223\215\345\272\224\347\273\223\346\236\234\350\275\254\346\215\242.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\345\223\215\345\272\224\347\273\223\346\236\234\350\275\254\346\215\242.md" new file mode 100644 index 00000000..edbba1a7 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\345\223\215\345\272\224\347\273\223\346\236\234\350\275\254\346\215\242.md" @@ -0,0 +1,171 @@ +# 响应结果转换 + + +**本文档引用的文件** +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java) +- [JdbcResponseConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java) +- [ResultListWithColumns.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultListWithColumns.java) +- [ListWithQueryColumn.java](file://datavines-common/src/main/java/io/datavines/common/entity/ListWithQueryColumn.java) +- [QueryColumn.java](file://datavines-common/src/main/java/io/datavines/common/entity/QueryColumn.java) +- [MongodbConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 引言 +DataVines 是一个用于数据质量监控和治理的开源平台,其核心功能之一是统一处理来自不同数据源的查询响应。为了实现跨数据源的一致性,DataVines 设计了响应结果转换机制,通过 `ResponseConverter` 接口将各种原始查询结果标准化为统一的数据结构 `ResultListWithColumns`。该机制支持多种数据源类型,包括 JDBC 兼容数据库、MongoDB 等 NoSQL 数据库以及文件系统等。本文档深入解析这一转换机制,重点阐述其设计原理、实现细节及扩展能力。 + +## 核心组件 +响应结果转换机制的核心在于 `ResponseConverter` 接口及其具体实现类。该接口定义了将原始查询结果转换为标准格式的方法契约,而具体的转换逻辑则由针对不同数据源的实现类完成。主要涉及的类包括 `ResponseConverter` 接口、`JdbcResponseConverter` 实现类、`ResultListWithColumns` 结果容器以及 `QueryColumn` 列元数据模型。 + +**核心组件** +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java#L1-L20) +- [JdbcResponseConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java#L1-L22) +- [ResultListWithColumns.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultListWithColumns.java#L1-L42) +- [ListWithQueryColumn.java](file://datavines-common/src/main/java/io/datavines/common/entity/ListWithQueryColumn.java#L1-L38) +- [QueryColumn.java](file://datavines-common/src/main/java/io/datavines/common/entity/QueryColumn.java#L1-L47) + +## 架构概述 +响应结果转换机制采用接口驱动的设计模式,通过定义统一的 `ResponseConverter` 接口,允许为不同的数据源提供定制化的转换器实现。当执行查询操作时,系统根据数据源类型选择相应的转换器,将原始结果(如 JDBC 的 `ResultSet` 或 MongoDB 的 `Document`)转换为标准的 `ResultListWithColumns` 对象。此对象不仅包含数据行列表,还封装了列的元数据信息,如名称、类型和注释,从而实现了结果的标准化和可移植性。 + +```mermaid +graph TB +subgraph "数据源" +A[JDBC 数据库] +B[MongoDB] +C[文件系统] +end +subgraph "转换器实现" +D[JdbcResponseConverter] +E[MongoDbResponseConverter] +F[FileResponseConverter] +end +subgraph "核心接口" +G[ResponseConverter] +end +subgraph "标准化结果" +H[ResultListWithColumns] +I[QueryColumn] +end +A --> D +B --> E +C --> F +D --> G +E --> G +F --> G +G --> H +H --> I +``` + +**图示来源** +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java#L1-L20) +- [JdbcResponseConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java#L1-L22) +- [ResultListWithColumns.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultListWithColumns.java#L1-L42) +- [QueryColumn.java](file://datavines-common/src/main/java/io/datavines/common/entity/QueryColumn.java#L1-L47) + +## 详细组件分析 +### ResponseConverter 接口分析 +`ResponseConverter` 接口是整个转换机制的基石,它定义了所有转换器必须遵循的契约。尽管当前接口定义为空,但其设计意图是作为所有具体转换器的抽象基类,确保系统可以通过多态性调用不同数据源的转换逻辑。这种设计提高了系统的可扩展性,使得新增数据源支持变得简单而安全。 + +**组件分析** +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java#L1-L20) + +### JdbcResponseConverter 实现分析 +`JdbcResponseConverter` 是针对 JDBC 数据源的具体转换器实现。它负责将 `java.sql.ResultSet` 对象转换为 `ResultListWithColumns`。转换过程包括两个主要步骤:首先,从 `ResultSetMetaData` 中提取列的名称、类型等元数据,构建 `QueryColumn` 对象列表;其次,遍历 `ResultSet` 的每一行,将每列的值转换为适当的 Java 对象(如 String、Integer、Boolean 等),并存入 `Map` 中,最终形成一个包含所有数据行的列表。此过程还处理了 NULL 值和特殊字符的转义,确保数据的完整性和一致性。 + +```mermaid +flowchart TD +Start([开始]) --> ExtractMetadata["提取列元数据
从 ResultSetMetaData"] +ExtractMetadata --> CreateQueryColumns["创建 QueryColumn 对象列表"] +CreateQueryColumns --> IterateRows["遍历 ResultSet 的每一行"] +IterateRows --> ProcessRow["处理当前行"] +ProcessRow --> GetColumnValue["获取每列的值"] +GetColumnValue --> HandleNull{"值为 NULL?"} +HandleNull --> |是| SetNull["设置为 null"] +HandleNull --> |否| ConvertType["根据 SQL 类型转换为 Java 类型"] +ConvertType --> AddToMap["将值添加到行 Map 中"] +AddToMap --> NextColumn["处理下一列"] +NextColumn --> MoreColumns{"还有更多列?"} +MoreColumns --> |是| GetColumnValue +MoreColumns --> |否| AddRowToList["将行 Map 添加到 resultList"] +AddRowToList --> NextRow{"还有更多行?"} +NextRow --> |是| IterateRows +NextRow --> |否| CreateResultList["创建 ResultListWithColumns 对象"] +CreateResultList --> End([结束]) +``` + +**图示来源** +- [JdbcResponseConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java#L1-L22) +- [ResultListWithColumns.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultListWithColumns.java#L1-L42) +- [QueryColumn.java](file://datavines-common/src/main/java/io/datavines/common/entity/QueryColumn.java#L1-L47) + +### MongoDB 数据源特殊规则分析 +对于 MongoDB 这类 NoSQL 数据源,由于其模式灵活,没有固定的表结构,因此无法像关系型数据库那样直接获取列元数据。`MongodbConnector` 类中的 `getColumns` 方法采用了启发式的方法来推断列的元数据。它通过查询集合中的一个文档(通常是最近插入的),遍历其所有键值对,根据值的 Java 类型(如 String、Integer、Boolean 等)来猜测其数据类型,并生成相应的 `ColumnInfo`。这种方法虽然不能保证 100% 的准确性(例如,无法区分 INT 和 BIGINT),但在大多数场景下足以提供有用的信息。对于 `_id` 字段,通常会特别处理,不将其作为普通列返回。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Connector as "MongodbConnector" +participant DB as "MongoDB" +Client->>Connector : getColumns(GetColumnsRequestParam) +Connector->>DB : db.getCollection(table).find().sort({_id : -1}).limit(1) +DB-->>Connector : 返回一个 Document +alt Document 存在 +Connector->>Connector : 遍历 Document 的每个键值对 +loop 每个键值对 +Connector->>Connector : key != "_id"? +alt 是 +Connector->>Connector : guessFieldType(value) +Connector->>Connector : 创建 ColumnInfo(key, fieldType) +end +end +Connector->>Client : 返回包含列信息的 ConnectorResponse +else Document 不存在 +Connector->>Client : 返回空的列信息列表 +end +``` + +**图示来源** +- [MongodbConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java#L130-L166) +- [QueryColumn.java](file://datavines-common/src/main/java/io/datavines/common/entity/QueryColumn.java#L1-L47) + +## 依赖分析 +响应结果转换机制的实现依赖于多个模块和外部库。核心依赖包括 `datavines-connector-api` 模块提供的接口定义,`datavines-common` 模块提供的通用实体和工具类,以及针对特定数据源的插件模块(如 `datavines-connector-jdbc` 和 `datavines-connector-mongodb`)。对于 MongoDB 支持,还需要引入 `mongodb-driver-sync` 作为外部依赖。这种模块化的设计使得各组件之间的耦合度较低,便于独立开发和测试。 + +```mermaid +graph TD +A[ResponseConverter] --> B[datavines-connector-api] +C[JdbcResponseConverter] --> D[datavines-connector-jdbc] +E[MongodbConnector] --> F[datavines-connector-mongodb] +D --> B +F --> B +B --> G[datavines-common] +F --> H[mongodb-driver-sync] +``` + +**图示来源** +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/pom.xml#L27-L57) +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java#L1-L20) +- [JdbcResponseConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java#L1-L22) +- [MongodbConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java#L47-L222) + +## 性能考虑 +在处理大数据量结果集时,响应结果转换机制需要考虑内存消耗和处理效率。理想情况下,应采用流式处理(streaming)的方式,避免一次性将所有数据加载到内存中。然而,根据现有代码分析,当前的实现似乎是将整个结果集完全加载后才进行转换,这在处理超大规模数据时可能会导致内存溢出(OOM)。未来的优化方向可以是引入分页机制或支持流式 API,允许客户端逐批获取和处理数据。此外,对于频繁的类型转换和字符串操作,应进行性能剖析,以识别和消除潜在的性能瓶颈。 + +## 故障排除指南 +在使用响应结果转换功能时,可能遇到的常见问题包括:数据类型映射错误、NULL 值处理异常、特殊字符乱码以及大数据量查询超时。排查这些问题时,应首先检查数据源连接配置是否正确,然后验证查询语句的语法。对于类型映射问题,需要确认 `JdbcResponseConverter` 中的类型映射逻辑是否与目标数据库兼容。如果遇到性能问题,应检查系统资源使用情况,并考虑优化查询或启用分页。日志文件是诊断问题的关键,应仔细审查 `datavines-server` 和相关 connector 的日志输出。 + +**故障排除** +- [MongodbConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java#L82-L83) +- [JdbcResponseConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java) + +## 结论 +DataVines 的响应结果转换机制通过 `ResponseConverter` 接口和 `ResultListWithColumns` 数据结构,成功实现了对多源异构数据查询结果的标准化。该设计具有良好的扩展性和清晰的职责划分。`JdbcResponseConverter` 提供了对关系型数据库的成熟支持,而 `MongodbConnector` 则展示了如何为 NoSQL 数据源设计适配方案。尽管在流式处理大结果集方面仍有改进空间,但整体架构为数据质量监控平台的稳定运行奠定了坚实的基础。未来的工作可以集中在性能优化和增强对更多数据源的支持上。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256.md" new file mode 100644 index 00000000..ec5e3fba --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256.md" @@ -0,0 +1,287 @@ +# 数据通信协议 + + +**本文档中引用的文件** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java) +- [ResultListWithColumns.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultListWithColumns.java) +- [ResultList.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultList.java) +- [ExecuteRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/ExecuteRequestParam.java) +- [ConnectorResponse.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [JdbcResponseConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java) +- [FileExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileExecutor.java) +- [MongodbExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbExecutor.java) +- [QueryColumn.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/QueryColumn.java) +- [ListWithQueryColumn.java](file://datavines-common/src/main/java/io/datavines/common/entity/ListWithQueryColumn.java) + + +## 目录 +1. [引言](#引言) +2. [核心接口设计](#核心接口设计) +3. [请求与响应结构](#请求与响应结构) +4. [数据源响应转换策略](#数据源响应转换策略) +5. [结果统一格式转换机制](#结果统一格式转换机制) +6. [SQL执行与元数据提取](#sql执行与元数据提取) +7. [协议通用性与扩展性分析](#协议通用性与扩展性分析) +8. [结论](#结论) + +## 引言 +DataVines作为一个数据质量监控平台,其核心组件Engine与Connector之间的数据通信协议是系统架构的关键部分。该协议定义了数据查询、执行和结果返回的标准方式,支持多种数据源类型(JDBC、文件、NoSQL等)。本文档深入剖析这一通信协议的设计原理与实现机制,重点分析Executor接口、Request/Response对象结构、响应结果转换策略以及协议的通用性和扩展性。 + +## 核心接口设计 + +DataVines通过`Executor`接口定义了Engine与Connector之间的核心交互契约。该接口位于`io.datavines.connector.api.Executor`,采用策略模式为不同数据源提供统一的执行入口。 + +```mermaid +classDiagram +class Executor { +<> ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse ++deleteData(ExecuteRequestParam) ConnectorResponse +} +class BaseJdbcExecutor { +-dataSourceClient DataSourceClient ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse +} +class FileExecutor { ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse +} +class MongodbExecutor { ++getDatasourceInfo(Map) BaseJdbcDataSourceInfo +} +Executor <|.. BaseJdbcExecutor +Executor <|.. FileExecutor +BaseJdbcExecutor <|-- MongodbExecutor +``` + +**图示来源** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [FileExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileExecutor.java) +- [MongodbExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbExecutor.java) + +**本节来源** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java#L24-L46) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java#L34-L116) + +## 请求与响应结构 + +### 请求对象设计 +`ExecuteRequestParam`类定义了查询请求的数据结构,继承自`ConnectorRequestParam`,包含执行脚本、变量、分页参数等核心字段。 + +```mermaid +classDiagram +class ExecuteRequestParam { +-script String +-variables String +-limit int +-pageNumber int +-pageSize int +} +class ConnectorRequestParam { +<> +-dataSourceParam String +} +ExecuteRequestParam --|> ConnectorRequestParam +``` + +**图示来源** +- [ExecuteRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/ExecuteRequestParam.java) + +**本节来源** +- [ExecuteRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/ExecuteRequestParam.java#L24-L35) + +### 响应对象设计 +`ConnectorResponse`采用构建者模式(Builder Pattern)设计,封装了执行状态、结果数据和错误信息三个核心部分,确保了响应的一致性和可扩展性。 + +```mermaid +classDiagram +class ConnectorResponse { +-status Status +-result Object +-errorMsg String ++getStatus() Status ++setStatus(Status) void ++getResult() Object ++setResult(Object) void ++getErrorMsg() String ++setErrorMsg(String) void +} +class Status { +<> +IN_PROGRESS +SUCCESS +ERROR +} +ConnectorResponse --> Status +``` + +**图示来源** +- [ConnectorResponse.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java) + +**本节来源** +- [ConnectorResponse.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java#L22-L90) + +## 数据源响应转换策略 + +DataVines针对不同类型数据源(JDBC、文件、NoSQL)设计了差异化的响应处理策略,但通过统一的接口保持了协议的一致性。 + +### JDBC数据源处理 +对于JDBC数据源,`BaseJdbcExecutor`作为抽象基类,封装了JDBC连接管理和SQL执行的通用逻辑。它通过`DataSourceClient`获取`JdbcTemplate`,并利用`SqlUtils`工具类执行查询。 + +### 文件数据源处理 +`FileExecutor`专门处理文件类型数据源,支持CSV等格式的文件读取。它通过解析文件路径和分隔符,将文件内容转换为结构化数据。 + +### MongoDB数据源处理 +`MongodbExecutor`继承自`BaseJdbcExecutor`,复用JDBC连接管理机制,但通过`MongodbDataSourceInfo`适配MongoDB特有的连接参数。 + +```mermaid +flowchart TD +A[执行请求] --> B{数据源类型} +B --> |JDBC| C[BaseJdbcExecutor] +B --> |文件| D[FileExecutor] +B --> |MongoDB| E[MongodbExecutor] +C --> F[JdbcTemplate] +D --> G[文件系统] +E --> H[MongoDB连接] +F --> I[SQL执行] +G --> J[文件解析] +H --> K[MongoDB查询] +I --> L[结果转换] +J --> L +K --> L +L --> M[统一响应格式] +``` + +**图示来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [FileExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileExecutor.java) +- [MongodbExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbExecutor.java) + +**本节来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java#L47-L115) +- [FileExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileExecutor.java#L41-L162) +- [MongodbExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbExecutor.java#L24-L34) + +## 结果统一格式转换机制 + +### 核心数据结构 +DataVines通过`ResultListWithColumns`类实现查询结果的标准化表示,继承自`ResultList`,增加了列元数据信息。 + +```mermaid +classDiagram +class ResultList { +-resultList Map[]String, Object~~ ++getResultList() Map[]String, Object~~ ++setResultList(Map[]String, Object~~) void +} +class ResultListWithColumns { +-columns QueryColumn[] ++getColumns() QueryColumn[] ++setColumns(QueryColumn[]) void +} +ResultList <|-- ResultListWithColumns +ResultListWithColumns --> QueryColumn +``` + +**图示来源** +- [ResultList.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultList.java) +- [ResultListWithColumns.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultListWithColumns.java) +- [QueryColumn.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/QueryColumn.java) + +**本节来源** +- [ResultList.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultList.java#L24-L41) +- [ResultListWithColumns.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultListWithColumns.java#L22-L42) +- [QueryColumn.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/QueryColumn.java#L19-L58) + +### 转换流程 +`ResponseConverter`接口定义了原始查询结果到`ResultListWithColumns`的转换契约。不同数据源实现各自的转换器,如`JdbcResponseConverter`负责将JDBC ResultSet转换为标准格式。 + +```mermaid +sequenceDiagram +participant Engine as Engine +participant Executor as Executor +participant DataSource as 数据源 +participant Converter as ResponseConverter +Engine->>Executor : executeQuery(request) +Executor->>DataSource : 执行查询 +DataSource-->>Executor : 原始结果 +Executor->>Converter : 转换结果 +Converter-->>Executor : ResultListWithColumns +Executor-->>Engine : ConnectorResponse +``` + +**图示来源** +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java) +- [JdbcResponseConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java) + +**本节来源** +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java#L19-L20) +- [JdbcResponseConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java#L21-L22) + +## SQL执行与元数据提取 + +### 执行过程 +SQL执行过程遵循严格的错误处理和资源管理规范。`BaseJdbcExecutor`在执行前验证参数,通过`JdbcTemplate`执行SQL,并处理可能的`SQLException`。 + +### 元数据提取 +查询结果的元数据(列名、类型等)通过`QueryColumn`对象封装。对于JDBC数据源,这些信息从ResultSetMetaData提取;对于文件数据源,则从文件头行解析。 + +```mermaid +flowchart TD +A[开始执行] --> B[参数验证] +B --> C{SQL是否为空} +C --> |是| D[返回错误] +C --> |否| E[获取数据库连接] +E --> F[执行SQL查询] +F --> G{查询成功} +G --> |否| H[捕获异常] +H --> I[返回错误响应] +G --> |是| J[提取结果集] +J --> K[提取元数据] +K --> L[转换为ResultListWithColumns] +L --> M[构建响应] +M --> N[返回结果] +``` + +**本节来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java#L47-L115) +- [FileExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileExecutor.java#L117-L160) + +## 协议通用性与扩展性分析 + +### 通用性设计 +DataVines的数据通信协议通过以下设计确保通用性: +1. **接口抽象**:`Executor`接口定义了统一的执行契约 +2. **参数泛化**:`ExecuteRequestParam`通过`dataSourceParam`支持任意数据源配置 +3. **响应标准化**:`ConnectorResponse`封装了所有可能的执行结果 + +### 扩展性机制 +协议的扩展性体现在: +1. **插件化架构**:通过SPI机制加载不同数据源的Connector +2. **继承复用**:`BaseJdbcExecutor`为所有JDBC兼容数据源提供基础实现 +3. **策略模式**:`ResponseConverter`允许不同数据源自定义转换逻辑 + +```mermaid +graph TD +A[新数据源] --> B[实现Executor接口] +B --> C[实现ResponseConverter] +C --> D[注册到SPI] +D --> E[自动发现] +E --> F[集成到系统] +``` + +**本节来源** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java) + +## 结论 +DataVines的数据通信协议通过精心设计的接口抽象、标准化的数据结构和灵活的扩展机制,实现了Engine与Connector之间的高效、可靠通信。该协议不仅支持多种数据源类型,还通过统一的响应格式和错误处理机制,为上层应用提供了简洁一致的API。其插件化架构和继承复用设计,使得新数据源的集成变得简单高效,体现了良好的软件工程实践。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\350\257\267\346\261\202\345\244\204\347\220\206\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\350\257\267\346\261\202\345\244\204\347\220\206\346\234\272\345\210\266.md" new file mode 100644 index 00000000..be17f002 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\350\257\267\346\261\202\345\244\204\347\220\206\346\234\272\345\210\266.md" @@ -0,0 +1,278 @@ +# 请求处理机制 + + +**本文档引用的文件** +- [Executor.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\Executor.java) +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java) +- [MongodbExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mongodb\src\main\java\io\datavines\connector\plugin\MongodbExecutor.java) +- [ExecuteRequestParam.java](file://datavines-common\src\main\java\io\datavines\common\param\ExecuteRequestParam.java) +- [ConnectorResponse.java](file://datavines-common\src\main\java\io\datavines\common\param\ConnectorResponse.java) +- [ConnectorRequestParam.java](file://datavines-common\src\main\java\io\datavines\common\param\ConnectorRequestParam.java) +- [DataSourceClient.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\DataSourceClient.java) +- [FileExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileExecutor.java) +- [MysqlExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlExecutor.java) +- [PostgreSqlExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlExecutor.java) +- [JobExecutionRequest.java](file://datavines-common\src\main\java\io\datavines\common\entity\JobExecutionRequest.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件](#核心组件) +3. [Executor接口设计原理](#executor接口设计原理) +4. [EngineExecutor请求封装与转发](#engineexecutor请求封装与转发) +5. [JDBC数据源请求处理](#jdbc数据源请求处理) +6. [MongoDB数据源请求处理](#mongodb数据源请求处理) +7. [文件数据源请求处理](#文件数据源请求处理) +8. [请求参数解析与执行计划](#请求参数解析与执行计划) +9. [调用链分析](#调用链分析) +10. [结论](#结论) + +## 引言 +DataVines是一个数据质量监控平台,其核心功能之一是处理各种数据源的查询请求。本文档详细阐述了DataVines中数据查询请求的处理流程,重点分析了Executor接口的设计原理及其executeQuery方法的参数定义,包括SQL语句、连接配置和执行上下文的传递机制。同时,描述了EngineExecutor如何封装执行请求并转发给底层Connector,以及不同类型数据源(如JDBC、MongoDB)对请求的差异化处理策略。通过JdbcExecutor和MongodbExecutor的具体实现,说明请求参数的解析、SQL语句的预处理和执行计划的生成过程,并提供实际代码示例展示请求从API层到数据源的完整调用链。 + +## 核心组件 +DataVines的数据查询请求处理涉及多个核心组件,主要包括Executor接口、各种数据源的Executor实现(如JdbcExecutor、MongodbExecutor)、DataSourceClient以及相关的参数和响应类。这些组件协同工作,实现了从API请求到数据源执行的完整流程。 + +**本文档引用的文件** +- [Executor.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\Executor.java) +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java) +- [MongodbExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mongodb\src\main\java\io\datavines\connector\plugin\MongodbExecutor.java) + +## Executor接口设计原理 +Executor接口是DataVines中数据查询请求处理的核心接口,定义了查询操作的基本方法。该接口采用默认方法(default method)的方式提供了查询操作的默认实现,允许具体的Executor实现类根据需要重写这些方法。 + +```mermaid +classDiagram +class Executor { +<> ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse ++deleteData(ExecuteRequestParam) ConnectorResponse +} +class BaseJdbcExecutor { +-dataSourceClient DataSourceClient ++BaseJdbcExecutor(DataSourceClient) ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse +} +class MongodbExecutor { ++MongodbExecutor(DataSourceClient) ++getDatasourceInfo(Map) BaseJdbcDataSourceInfo +} +class FileExecutor { ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse +} +Executor <|-- BaseJdbcExecutor +Executor <|-- MongodbExecutor +Executor <|-- FileExecutor +BaseJdbcExecutor <|-- MongodbExecutor +BaseJdbcExecutor <|-- MysqlExecutor +BaseJdbcExecutor <|-- PostgreSqlExecutor +``` + +**图表来源** +- [Executor.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\Executor.java) +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java) +- [MongodbExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mongodb\src\main\java\io\datavines\connector\plugin\MongodbExecutor.java) +- [FileExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileExecutor.java) +- [MysqlExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlExecutor.java) +- [PostgreSqlExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlExecutor.java) + +**本节来源** +- [Executor.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\Executor.java) + +## EngineExecutor请求封装与转发 +EngineExecutor是DataVines中负责执行任务的核心接口,它定义了任务执行的生命周期方法,包括初始化、执行、后续处理、取消和状态检查。EngineExecutor通过PluginLoader机制动态加载具体的执行器实现,并将请求封装后转发给底层的Connector进行处理。 + +```mermaid +sequenceDiagram +participant API as API控制器 +participant JobRunner as JobRunner +participant PluginLoader as PluginLoader +participant EngineExecutor as EngineExecutor +participant ConnectorFactory as ConnectorFactory +participant Executor as Executor +API->>JobRunner : 提交执行请求 +JobRunner->>PluginLoader : 加载EngineExecutor插件 +PluginLoader-->>JobRunner : 返回EngineExecutor实例 +JobRunner->>EngineExecutor : 初始化 +JobRunner->>EngineExecutor : 执行 +EngineExecutor->>ConnectorFactory : 获取Connector工厂 +ConnectorFactory-->>EngineExecutor : 返回Executor实例 +EngineExecutor->>Executor : 调用查询方法 +Executor-->>EngineExecutor : 返回查询结果 +EngineExecutor-->>JobRunner : 返回执行结果 +JobRunner-->>API : 返回响应 +``` + +**图表来源** +- [JobRunner.java](file://datavines-runner\src\main\java\io\datavines\runner\JobRunner.java) +- [EngineExecutor.java](file://datavines-engine\datavines-engine-api\src\main\java\io\datavines\engine\api\engine\EngineExecutor.java) +- [ConnectorFactory.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\ConnectorFactory.java) + +**本节来源** +- [EngineExecutor.java](file://datavines-engine\datavines-engine-api\src\main\java\io\datavines\engine\api\engine\EngineExecutor.java) +- [JobRunner.java](file://datavines-runner\src\main\java\io\datavines\runner\JobRunner.java) + +## JDBC数据源请求处理 +对于JDBC数据源,DataVines通过BaseJdbcExecutor类提供了基础的查询处理功能。该类实现了Executor接口,并提供了对分页查询、单条查询和列表查询的支持。具体的数据库类型(如MySQL、PostgreSQL)通过继承BaseJdbcExecutor并重写getDatasourceInfo方法来实现特定的数据源信息解析。 + +```mermaid +flowchart TD +Start([开始]) --> ValidateInput["验证输入参数"] +ValidateInput --> InputValid{"参数有效?"} +InputValid --> |否| ReturnError["返回错误响应"] +InputValid --> |是| ParseDataSource["解析数据源参数"] +ParseDataSource --> GetDataSourceInfo["获取数据源信息"] +GetDataSourceInfo --> CreateJdbcTemplate["创建JdbcTemplate"] +CreateJdbcTemplate --> ExecuteQuery["执行SQL查询"] +ExecuteQuery --> ProcessResult["处理查询结果"] +ProcessResult --> ReturnResult["返回结果"] +ReturnError --> End([结束]) +ReturnResult --> End +``` + +**图表来源** +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java) +- [MysqlExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlExecutor.java) +- [PostgreSqlExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlExecutor.java) + +**本节来源** +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java) + +## MongoDB数据源请求处理 +对于MongoDB数据源,DataVines通过MongodbExecutor类实现了查询处理。MongodbExecutor继承自BaseJdbcExecutor,利用JDBC连接MongoDB的方式进行数据查询。它通过重写getDatasourceInfo方法来解析MongoDB特有的连接参数,并使用标准的JDBC接口执行查询操作。 + +```mermaid +classDiagram +class MongodbExecutor { ++MongodbExecutor(DataSourceClient) ++getDatasourceInfo(Map) BaseJdbcDataSourceInfo +} +class MongodbDataSourceInfo { ++MongodbDataSourceInfo(Map) ++getJdbcUrl() String ++getUserName() String ++getPassword() String +} +MongodbExecutor --> MongodbDataSourceInfo : "使用" +``` + +**图表来源** +- [MongodbExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mongodb\src\main\java\io\datavines\connector\plugin\MongodbExecutor.java) +- [MongodbDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\entity\MongodbDataSourceInfo.java) + +**本节来源** +- [MongodbExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mongodb\src\main\java\io\datavines\connector\plugin\MongodbExecutor.java) + +## 文件数据源请求处理 +对于文件数据源,DataVines通过FileExecutor类实现了基于文件系统的查询处理。FileExecutor直接实现了Executor接口,支持对CSV等格式文件的分页查询和单条查询。它通过解析文件路径和列分隔符等参数,读取文件内容并返回结构化的查询结果。 + +```mermaid +flowchart TD +Start([开始]) --> ValidateInput["验证输入参数"] +ValidateInput --> InputValid{"参数有效?"} +InputValid --> |否| ReturnError["返回错误响应"] +InputValid --> |是| ParseFilePath["解析文件路径"] +ParseFilePath --> CheckFileExist["检查文件是否存在"] +CheckFileExist --> FileExists{"文件存在?"} +FileExists --> |否| ReturnError +FileExists --> |是| ReadFileContent["读取文件内容"] +ReadFileContent --> ParseHeader["解析文件头"] +ParseHeader --> ExtractData["提取数据"] +ExtractData --> ReturnResult["返回结果"] +ReturnError --> End([结束]) +ReturnResult --> End +``` + +**图表来源** +- [FileExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileExecutor.java) + +**本节来源** +- [FileExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileExecutor.java) + +## 请求参数解析与执行计划 +DataVines中的请求参数解析和执行计划生成主要通过ExecuteRequestParam类和相关的Executor实现来完成。ExecuteRequestParam封装了查询请求的所有必要信息,包括SQL脚本、变量、分页参数等。Executor实现类根据这些参数生成相应的执行计划,并通过DataSourceClient获取数据源连接来执行查询。 + +```mermaid +classDiagram +class ExecuteRequestParam { ++script String ++variables String ++limit int ++pageNumber int ++pageSize int +} +class ConnectorRequestParam { ++type String ++dataSourceParam String +} +class ConnectorResponse { ++status Status ++result Object ++errorMsg String +} +class DataSourceClient { +<> ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getConnection(BaseJdbcDataSourceInfo) Connection ++getJdbcTemplate(BaseJdbcDataSourceInfo) JdbcTemplate +} +ExecuteRequestParam --|> ConnectorRequestParam : "继承" +ConnectorResponse : 枚举 Status {IN_PROGRESS, SUCCESS, ERROR} +DataSourceClient ..> BaseJdbcDataSourceInfo : "使用" +``` + +**图表来源** +- [ExecuteRequestParam.java](file://datavines-common\src\main\java\io\datavines\common\param\ExecuteRequestParam.java) +- [ConnectorRequestParam.java](file://datavines-common\src\main\java\io\datavines\common\param\ConnectorRequestParam.java) +- [ConnectorResponse.java](file://datavines-common\src\main\java\io\datavines\common\param\ConnectorResponse.java) +- [DataSourceClient.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\DataSourceClient.java) + +**本节来源** +- [ExecuteRequestParam.java](file://datavines-common\src\main\java\io\datavines\common\param\ExecuteRequestParam.java) +- [ConnectorResponse.java](file://datavines-common\src\main\java\io\datavines\common\param\ConnectorResponse.java) +- [DataSourceClient.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\DataSourceClient.java) + +## 调用链分析 +DataVines的数据查询请求从API层到数据源的完整调用链如下:API控制器接收请求后,通过JobRunner启动任务执行,JobRunner使用PluginLoader加载相应的EngineExecutor实现,EngineExecutor初始化后执行任务,通过ConnectorFactory获取对应的Executor实例,Executor实例根据请求参数执行具体的查询操作,并将结果返回给上层调用者。 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant API as API控制器 +participant JobRunner as JobRunner +participant EngineExecutor as EngineExecutor +participant ConnectorFactory as ConnectorFactory +participant Executor as Executor +participant DataSource as 数据源 +Client->>API : 发送查询请求 +API->>JobRunner : 提交执行请求 +JobRunner->>EngineExecutor : 初始化执行器 +EngineExecutor->>ConnectorFactory : 获取Executor +ConnectorFactory-->>EngineExecutor : 返回Executor实例 +EngineExecutor->>Executor : 执行查询 +Executor->>DataSource : 执行SQL +DataSource-->>Executor : 返回结果 +Executor-->>EngineExecutor : 返回查询结果 +EngineExecutor-->>JobRunner : 返回执行结果 +JobRunner-->>API : 返回响应 +API-->>Client : 返回查询结果 +``` + +**图表来源** +- [JobExecutionController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\JobExecutionController.java) +- [JobRunner.java](file://datavines-runner\src\main\java\io\datavines\runner\JobRunner.java) +- [EngineExecutor.java](file://datavines-engine\datavines-engine-api\src\main\java\io\datavines\engine\api\engine\EngineExecutor.java) +- [ConnectorFactory.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\ConnectorFactory.java) +- [Executor.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\Executor.java) + +**本节来源** +- [JobRunner.java](file://datavines-runner\src\main\java\io\datavines\runner\JobRunner.java) +- [JobExecutionRequest.java](file://datavines-common\src\main\java\io\datavines\common\entity\JobExecutionRequest.java) + +## 结论 +DataVines通过精心设计的Executor接口和灵活的插件机制,实现了对多种数据源的统一查询处理。Executor接口提供了标准化的查询方法,而具体的Executor实现类则负责处理特定数据源的细节。EngineExecutor作为任务执行的核心,通过封装和转发请求,实现了请求处理的解耦和灵活性。通过对JDBC、MongoDB和文件数据源的差异化处理策略,DataVines能够高效地处理各种类型的数据查询请求,为数据质量监控提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\351\224\231\350\257\257\345\244\204\347\220\206\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\351\224\231\350\257\257\345\244\204\347\220\206\347\255\226\347\225\245.md" new file mode 100644 index 00000000..18d96f5c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\346\225\260\346\215\256\351\200\232\344\277\241\345\215\217\350\256\256/\351\224\231\350\257\257\345\244\204\347\220\206\347\255\226\347\225\245.md" @@ -0,0 +1,582 @@ +# 错误处理策略 + + +**本文档引用的文件** +- [DataVinesException.java](file://datavines-common/src/main/java/io/datavines/common/exception/DataVinesException.java) +- [DataVinesServerException.java](file://datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java) +- [Status.java](file://datavines-core/src/main/java/io/datavines/core/enums/Status.java) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [RefreshToken.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshToken.java) +- [ConnectorResponse.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java) +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) +- [response.interceptor.ts](file://datavines-ui/Editor/http/response.interceptor.ts) + + +## 更新摘要 +**变更内容** +- 新增了DataVinesExceptionHandler中的令牌刷新功能增强 +- 改进了错误消息处理机制,增加了tryRefreshToken方法 +- 新增了RefreshTokenAop切面用于自动令牌刷新 +- 完善了令牌自动刷新机制,支持多种请求场景 + +## 目录 +1. [引言](#引言) +2. [异常分类与处理策略](#异常分类与处理策略) +3. [异常体系设计](#异常体系设计) +4. [错误信息标准化输出](#错误信息标准化输出) +5. [令牌自动刷新机制](#令牌自动刷新机制) +6. [错误传播链分析](#错误传播链分析) +7. [重试机制与故障隔离](#重试机制与故障隔离) +8. [前端错误处理](#前端错误处理) +9. [总结](#总结) + +## 引言 +DataVines作为一个数据质量监控平台,其错误处理机制是确保系统稳定性和用户体验的关键组成部分。本文档系统性地介绍DataVines的错误处理机制,重点分析在数据通信过程中各类异常的分类与处理策略,包括连接异常、SQL语法错误、超时异常和数据类型不匹配等。我们将深入探讨DataVinesException体系的设计原则,以及如何通过异常包装提供清晰的错误上下文信息。 + +**本文档引用的文件** +- [DataVinesException.java](file://datavines-common/src/main/java/io/datavines/common/exception/DataVinesException.java) +- [DataVinesServerException.java](file://datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java) + +## 异常分类与处理策略 +DataVines在数据通信过程中可能遇到多种异常情况,系统对这些异常进行了分类并制定了相应的处理策略。 + +### 连接异常 +当系统尝试连接数据源时,可能由于网络问题、认证失败或服务不可用等原因导致连接异常。这类异常通常由底层JDBC驱动抛出,DataVines通过JdbcDataSourceManager等组件进行捕获和处理。 + +### SQL语法错误 +在执行SQL查询时,如果SQL语句存在语法错误或引用了不存在的表或列,数据库会返回相应的错误信息。DataVines通过JdbcExecutorClient等组件执行SQL,并对执行结果进行分析,将SQL语法错误转换为系统可识别的异常类型。 + +### 超时异常 +长时间运行的查询可能导致超时异常。DataVines通过配置超时策略来处理此类问题,允许用户选择重试或警告等不同的处理方式。 + +### 数据类型不匹配 +当尝试将数据从一种类型转换为另一种类型时,如果转换不兼容,可能会发生数据类型不匹配异常。例如,在将字符串转换为数字时,如果字符串包含非数字字符,就会抛出此类异常。 + +```mermaid +flowchart TD +A[连接异常] --> B[网络问题] +A --> C[认证失败] +A --> D[服务不可用] +E[SQL语法错误] --> F[语法错误] +E --> G[表不存在] +E --> H[列不存在] +I[超时异常] --> J[查询超时] +I --> K[连接超时] +L[数据类型不匹配] --> M[字符串转数字] +L --> N[日期格式错误] +L --> O[类型转换失败] +``` + +**图源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [JdbcExecutorClient.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClient.java) + +**本节引用的文件** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [JdbcExecutorClient.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClient.java) + +## 异常体系设计 +DataVines的异常体系设计遵循了良好的面向对象原则,通过继承和封装提供了清晰的异常分类和处理机制。 + +### DataVinesException基础类 +`DataVinesException`是所有自定义异常的基类,继承自`RuntimeException`。它提供了多个构造函数,支持无参数、仅消息、消息和原因、仅原因以及完整的参数列表等不同的异常创建方式。 + +```java +public class DataVinesException extends RuntimeException { + public DataVinesException() { + super(); + } + + public DataVinesException(String message) { + super(message); + } + + public DataVinesException(String message, Throwable cause) { + super(message, cause); + } + + public DataVinesException(Throwable cause) { + super(cause); + } + + protected DataVinesException(String message, Throwable cause, + boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} +``` + +### DataVinesServerException扩展类 +`DataVinesServerException`继承自`DataVinesException`,并引入了`Status`枚举类型来表示具体的错误状态。这种设计使得异常不仅包含错误消息,还包含了结构化的错误代码和状态信息。 + +```mermaid +classDiagram +class DataVinesException { ++DataVinesException() ++DataVinesException(String message) ++DataVinesException(String message, Throwable cause) ++DataVinesException(Throwable cause) ++DataVinesException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) +} +class DataVinesServerException { +-Status status ++DataVinesServerException(String message) ++DataVinesServerException(String message, Throwable cause) ++DataVinesServerException(Throwable cause) ++DataVinesServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) ++DataVinesServerException(Status status) ++DataVinesServerException(Status status, Throwable cause) ++DataVinesServerException(Status status, Object... statusParams) ++getStatus() Status +} +DataVinesServerException --|> DataVinesException : 继承 +``` + +**图源** +- [DataVinesException.java](file://datavines-common/src/main/java/io/datavines/common/exception/DataVinesException.java) +- [DataVinesServerException.java](file://datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java) + +### Status枚举状态码 +`Status`枚举类定义了系统中所有可能的错误状态,每个状态包含唯一的错误代码、英文消息和中文消息。这种设计支持国际化,并且通过`getMsg()`方法根据当前语言环境返回相应的消息。 + +```java +public enum Status { + SUCCESS(200, "success", "成功"), + FAIL(400, "Bad Request", "错误的请求"), + REQUEST_ERROR(10010001, "Request Error", "请求错误"), + INVALID_TOKEN(10010002, "Invalid Token :{0}", "无效的Token :{0}"), + // ... 其他状态 +} +``` + +**本节引用的文件** +- [DataVinesException.java](file://datavines-common/src/main/java/io/datavines/common/exception/DataVinesException.java) +- [DataVinesServerException.java](file://datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java) +- [Status.java](file://datavines-core/src/main/java/io/datavines/core/enums/Status.java) + +## 错误信息标准化输出 +DataVines通过`ResultMap`类实现了错误信息的标准化输出,确保前后端之间的通信具有一致的格式。 + +### ResultMap结构 +`ResultMap`继承自`HashMap`,并添加了`code`字段来表示响应状态码。它提供了`success()`、`fail()`等方法来快速构建成功或失败的响应。 + +```java +public class ResultMap extends HashMap { + @Getter + private int code; + private TokenManager tokenManager; + + public ResultMap success() { + this.code = 200; + this.put("code", this.code); + this.put("msg", "Success"); + this.put("data", EMPTY); + return this; + } + + public ResultMap fail() { + this.code = 400; + this.put("code", code); + this.put("data", EMPTY); + return this; + } + + public ResultMap fail(int code) { + this.code = code; + this.put("code", code); + this.put("data", EMPTY); + return this; + } + + public ResultMap message(String message) { + this.put("msg", message); + return this; + } + + public ResultMap payload(Object object) { + this.put("data", null == object ? EMPTY : object); + return this; + } +} +``` + +### 统一异常处理 +`DataVinesExceptionHandler`作为全局异常处理器,通过`@RestControllerAdvice`注解拦截所有控制器抛出的异常,并将其转换为标准化的`ResultMap`响应。 + +**更新** DataVinesExceptionHandler现在集成了令牌自动刷新功能,通过tryRefreshToken方法在异常处理过程中自动刷新用户令牌。 + +```java +@RestControllerAdvice +public class DataVinesExceptionHandler { + @Resource + private TokenManager tokenManager; + + @ExceptionHandler(DataVinesServerException.class) + public ResponseEntity dataVinesServerExceptionHandler(DataVinesServerException e, HttpServletRequest request) { + log.error("DataVinesServerException:", e); + ResultMap resultMap = new ResultMap(tokenManager); + Status status = e.getStatus(); + if (Status.INVALID_TOKEN.equals(status)){ + return ResponseEntity.ok(new ResultMap().fail(Status.PLEASE_LOGIN.getCode()).message(Status.PLEASE_LOGIN.getMsg())); + } + + if (Status.TOKEN_IS_NULL_ERROR.equals(status)){ + return ResponseEntity.ok(new ResultMap().fail(Status.PLEASE_LOGIN.getCode()).message(Status.PLEASE_LOGIN.getMsg())); + } + + if (!Objects.isNull(status)) { + resultMap.fail(status.getCode()); + } else { + resultMap.fail(); + } + tryRefreshToken(request, resultMap); + resultMap.message(e.getMessage()); + return ResponseEntity.ok(resultMap); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity commonExceptionHandler(Exception e, HttpServletRequest request) { + log.error("Exception:", e); + ResultMap resultMap = new ResultMap(tokenManager); + resultMap.fail(); + tryRefreshToken(request, resultMap); + resultMap.message(e.getMessage()); + return ResponseEntity.ok(resultMap); + } + + private void tryRefreshToken(HttpServletRequest request, ResultMap resultMap) { + try { + String token = request.getHeader(DataVinesConstants.TOKEN_HEADER_STRING); + if (StringUtils.isEmpty(token)) { + token = (String) request.getAttribute(DataVinesConstants.TOKEN_HEADER_STRING); + if (StringUtils.isEmpty(token)) { + token = request.getParameter(DataVinesConstants.TOKEN_HEADER_STRING); + } + } + if (StringUtils.isNotEmpty(token) && tokenManager != null) { + resultMap.put("token", tokenManager.refreshToken(token)); + } + } catch (Exception ex) { + log.debug("Token refresh skipped: {}", ex.getMessage()); + } + } +} +``` + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Controller as 控制器 +participant ExceptionHandler as 异常处理器 +participant TokenManager as 令牌管理器 +participant ResultMap as ResultMap +Client->>Controller : 发送请求 +Controller->>Controller : 处理业务逻辑 +Controller->>ExceptionHandler : 抛出异常 +ExceptionHandler->>ExceptionHandler : 记录错误日志 +ExceptionHandler->>TokenManager : 尝试刷新令牌 +TokenManager-->>ExceptionHandler : 返回新令牌 +ExceptionHandler->>ResultMap : 创建ResultMap +ExceptionHandler->>ResultMap : 设置错误码和消息 +ResultMap->>ExceptionHandler : 返回ResultMap +ExceptionHandler->>Client : 返回标准化响应 +``` + +**图源** +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) + +**本节引用的文件** +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) + +## 令牌自动刷新机制 + +**新增** DataVines引入了完整的令牌自动刷新机制,通过多种组件协同工作来确保用户会话的连续性和安全性。 + +### TokenManager令牌管理 +`TokenManager`负责JWT令牌的生成、验证和刷新操作。它提供了多种令牌操作方法,包括生成新令牌、刷新现有令牌和验证令牌有效性。 + +```java +public class TokenManager { + // 生成新令牌 + public String generateToken(String username, String password) { + Map claims = new HashMap<>(); + claims.put(DataVinesConstants.TOKEN_USER_NAME, username); + claims.put(DataVinesConstants.TOKEN_USER_PASSWORD, password); + claims.put(DataVinesConstants.TOKEN_CREATE_TIME, System.currentTimeMillis()); + return generate(claims); + } + + // 刷新令牌 + public String refreshToken(String token) { + Claims claims = getClaims(token); + claims.put(DataVinesConstants.TOKEN_CREATE_TIME, System.currentTimeMillis()); + return generate(claims); + } + + // 验证令牌 + public boolean validateToken(String token, String username, String password) { + String tokenUsername = getUsername(token); + String tokenPassword = getPassword(token); + return (username.equals(tokenUsername) && password.equals(tokenPassword) && !(isExpired(token))); + } +} +``` + +### RefreshTokenAop切面 +`RefreshTokenAop`是一个Spring AOP切面,通过`@RefreshToken`注解标记的控制器会在每次请求后自动刷新令牌。 + +```java +@Aspect +@Component +@Order(Integer.MAX_VALUE) +public class RefreshTokenAop { + + @Pointcut("@within(RefreshToken)") + public void pointCut() { + } + + @Around(value = "pointCut()") + public Object doAroundReturningAdvice(ProceedingJoinPoint point) throws Throwable{ + Object[] args = point.getArgs(); + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + Object result = point.proceed(args); + return ResponseEntity.ok(new ResultMap(tokenManager).successAndRefreshToken(request).payload(result)); + } +} +``` + +### RefreshToken注解 +`RefreshToken`是一个简单的元注解,用于标记需要自动令牌刷新的控制器类。 + +```java +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RefreshToken { +} +``` + +### 自动刷新流程 +令牌自动刷新通过以下流程实现: + +```mermaid +sequenceDiagram +participant Controller as 控制器 +participant AOP as RefreshTokenAop +participant TokenManager as TokenManager +participant ResultMap as ResultMap +Controller->>AOP : 调用受保护的方法 +AOP->>AOP : 获取HttpServletRequest +AOP->>Controller : 执行目标方法 +Controller-->>AOP : 返回业务结果 +AOP->>TokenManager : 刷新令牌 +TokenManager-->>AOP : 返回新令牌 +AOP->>ResultMap : 构建成功响应 +ResultMap-->>AOP : 返回ResultMap +AOP-->>Controller : 返回响应 +``` + +**图源** +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [RefreshToken.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshToken.java) + +**本节引用的文件** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [RefreshToken.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshToken.java) + +## 错误传播链分析 +DataVines的错误传播链从底层数据源异常开始,经过多层处理,最终到达前端用户界面。 + +### 底层异常捕获 +在数据源连接和SQL执行过程中,底层JDBC驱动可能会抛出各种SQLException。这些异常首先被`JdbcDataSourceClient`和`JdbcExecutorClient`等组件捕获。 + +### 中间层包装 +捕获到底层异常后,DataVines会将其包装为更具体的`DataVinesException`子类,添加上下文信息,如数据源名称、SQL语句等。 + +### 服务层处理 +在服务层,`DataVinesServerException`被用来表示业务逻辑中的错误。这些异常包含了`Status`枚举,提供了结构化的错误信息。 + +### 控制器层转换 +**更新** 控制器层的`DataVinesExceptionHandler`现在集成了令牌自动刷新功能。在处理异常时,它会调用`tryRefreshToken`方法尝试刷新用户令牌,确保用户会话的连续性。 + +```java +private void tryRefreshToken(HttpServletRequest request, ResultMap resultMap) { + try { + String token = request.getHeader(DataVinesConstants.TOKEN_HEADER_STRING); + if (StringUtils.isEmpty(token)) { + token = (String) request.getAttribute(DataVinesConstants.TOKEN_HEADER_STRING); + if (StringUtils.isEmpty(token)) { + token = request.getParameter(DataVinesConstants.TOKEN_HEADER_STRING); + } + } + if (StringUtils.isNotEmpty(token) && tokenManager != null) { + resultMap.put("token", tokenManager.refreshToken(token)); + } + } catch (Exception ex) { + log.debug("Token refresh skipped: {}", ex.getMessage()); + } +} +``` + +### 前端接收与显示 +前端通过HTTP拦截器接收响应,根据`ResultMap`中的`code`字段判断请求是否成功,并显示相应的用户提示。 + +```mermaid +flowchart TD +A[底层SQLException] --> B[JdbcExecutorClient捕获] +B --> C[包装为DataVinesException] +C --> D[服务层抛出DataVinesServerException] +D --> E[DataVinesExceptionHandler处理] +E --> F[tryRefreshToken尝试刷新令牌] +F --> G[转换为ResultMap] +G --> H[返回JSON响应] +H --> I[前端HTTP拦截器] +I --> J[解析ResultMap] +J --> K[显示用户提示] +``` + +**图源** +- [JdbcExecutorClient.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClient.java) +- [DataVinesServerException.java](file://datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) + +**本节引用的文件** +- [JdbcExecutorClient.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClient.java) +- [DataVinesServerException.java](file://datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) + +## 重试机制与故障隔离 +DataVines通过`TimeoutStrategy`枚举实现了灵活的重试机制和故障隔离策略。 + +### TimeoutStrategy枚举 +`TimeoutStrategy`定义了两种处理策略:`RETRY`(重试)和`WARN`(警告)。用户可以在任务配置中选择合适的策略。 + +```java +public enum TimeoutStrategy{ + RETRY(0, "retry"), + WARN(1, "warn"); + + TimeoutStrategy(int code, String description){ + this.code = code; + this.description = description; + } + + final int code; + final String description; + + public int getCode() { + return code; + } + + public String getDescription() { + return description; + } +} +``` + +### 重试间隔配置 +在前端界面中,用户可以配置重试间隔时间,系统会根据这个配置在发生错误时进行重试。 + +```mermaid +stateDiagram-v2 +[*] --> Idle +Idle --> Processing : 开始执行 +Processing --> Success : 执行成功 +Processing --> Failed : 执行失败 +Failed --> Retry : 策略=RETRY +Failed --> Warning : 策略=WARN +Retry --> Processing : 等待重试间隔 +Warning --> [*] : 记录警告 +Success --> [*] : 完成 +``` + +**图源** +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) +- [index.tsx](file://datavines-ui/Editor/components/MetricModal/OtherConfig/index.tsx) + +**本节引用的文件** +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) +- [index.tsx](file://datavines-ui/Editor/components/MetricModal/OtherConfig/index.tsx) + +## 前端错误处理 +前端通过HTTP拦截器对响应进行统一处理,确保用户能够获得清晰的错误提示。 + +### 响应拦截器 +`responseOnSuccess`函数检查响应数据,如果`code`为200则认为请求成功,否则返回拒绝的Promise。 + +```typescript +export const responseOnSuccess = (response: IResponseInterface) => { + const { data } = response; + if (data) { + if (data instanceof Blob) { + return { + success: true, + data, + }; + } + if (data.code === 200) { + return data; + } + } + return Promise.reject({ + msg: data?.msg, + code: data?.code, + }); +}; +``` + +### 错误拦截器 +`responseOnError`函数处理请求错误,记录错误日志并返回拒绝的Promise。 + +```typescript +export const responseOnError = (error: any):any => { + console.log(error); + // eslint-disable-next-line no-underscore-dangle + if (error?.__CANCEL__) { + return; + } + return Promise.reject({ + msg: error?.msg || 'interface error', + code: null, + }); +}; +``` + +```mermaid +sequenceDiagram +participant Frontend as 前端 +participant Interceptor as 拦截器 +participant Backend as 后端 +Frontend->>Interceptor : 发送请求 +Interceptor->>Backend : 转发请求 +Backend->>Interceptor : 返回响应 +Interceptor->>Interceptor : 检查响应码 +alt 响应成功 +Interceptor->>Frontend : 返回数据 +else 响应失败 +Interceptor->>Frontend : 返回错误信息 +Frontend->>Frontend : 显示错误提示 +end +``` + +**图源** +- [response.interceptor.ts](file://datavines-ui/Editor/http/response.interceptor.ts) + +**本节引用的文件** +- [response.interceptor.ts](file://datavines-ui/Editor/http/response.interceptor.ts) + +## 总结 +DataVines的错误处理机制通过分层设计和标准化输出,实现了从底层数据源异常到前端用户提示的完整错误传播链。系统通过`DataVinesException`体系提供了清晰的异常分类,利用`Status`枚举实现了错误码的结构化管理,并通过`ResultMap`确保了前后端通信的一致性。 + +**更新** 最新的版本增强了异常处理机制,新增了DataVinesExceptionHandler中的令牌刷新功能。该功能通过tryRefreshToken方法在异常处理过程中自动刷新用户令牌,确保用户会话的连续性。同时,系统还引入了RefreshTokenAop切面和RefreshToken注解,实现了自动令牌刷新机制,支持多种请求场景。 + +全局异常处理器`DataVinesExceptionHandler`统一处理所有异常,而`TimeoutStrategy`则提供了灵活的重试机制。前端通过HTTP拦截器对响应进行统一处理,确保用户能够获得清晰的错误提示。这种设计不仅提高了系统的稳定性和可维护性,也极大地改善了用户体验。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\345\274\202\345\270\270\344\274\240\346\222\255\344\270\216\345\244\204\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\345\274\202\345\270\270\344\274\240\346\222\255\344\270\216\345\244\204\347\220\206.md" new file mode 100644 index 00000000..d788deb6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\345\274\202\345\270\270\344\274\240\346\222\255\344\270\216\345\244\204\347\220\206.md" @@ -0,0 +1,215 @@ +# 异常传播与处理 + + +**本文档引用的文件** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) +- [JobExecutionFailover.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\failover\JobExecutionFailover.java) +- [DataVinesException.java](file://datavines-common\src\main\java\io\datavines\common\exception\DataVinesException.java) +- [DataVinesServerException.java](file://datavines-core\src\main\java\io\datavines\core\exception\DataVinesServerException.java) +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java) +- [TimeoutStrategy.java](file://datavines-common\src\main\java\io\datavines\common\enums\TimeoutStrategy.java) +- [DqFailureStrategy.java](file://datavines-server\src\main\java\io\datavines\server\enums\DqFailureStrategy.java) + + +## 目录 +1. [引言](#引言) +2. [异常处理架构](#异常处理架构) +3. [LivyTaskSubmitHelper异常捕获机制](#livytasksubmithelper异常捕获机制) +4. [JobExecutionFailover故障转移策略](#jobexecutionfailover故障转移策略) +5. [异常信息分级处理](#异常信息分级处理) +6. [具体异常场景分析](#具体异常场景分析) +7. [结论](#结论) + +## 引言 +DataVines作为一个分布式数据质量监控系统,其异常处理机制是确保系统稳定性和可靠性的关键。本系统通过统一的异常处理框架,实现了对分布式环境中各种异常的捕获、转换、处理和恢复。核心组件包括LivyTaskSubmitHelper用于捕获外部计算框架异常,JobExecutionFailover实现故障转移和重试策略,以及基于不同异常类型的分级处理机制。 + +## 异常处理架构 + +```mermaid +classDiagram +class DataVinesException { ++DataVinesException() ++DataVinesException(String message) ++DataVinesException(String message, Throwable cause) ++DataVinesException(Throwable cause) +} +class DataVinesServerException { +-Status status ++DataVinesServerException(String message) ++DataVinesServerException(String message, Throwable cause) ++DataVinesServerException(Status status) ++DataVinesServerException(Status status, Throwable cause) ++Status getStatus() +} +class LivyTaskSubmitHelper { +-RestTemplate restTemplate +-String uri +-Configurations configurations ++LivyTaskSubmitHelper(Configurations configurations) ++void init() ++Map retryLivyGetAppId(String result, int appIdRetryCount) ++String postToLivy(String livyArgs) ++String getFromLivy(String uri) ++void deleteByLivy(Long sessionId, String appId) ++void deleteByYarn(String url, String appId) +} +class JobExecutionFailover { +-JobExternalService jobExternalService +-ConcurrentHashMap needCheckStatusJobExecutionMap +-JobExecuteManager jobExecuteManager +-ScheduledExecutorService executorService ++JobExecutionFailover(JobExecuteManager jobExecuteManager) ++void handleJobExecutionFailover(String host) ++void handleJobExecutionFailover(List hostList) +-void innerHandleJobExecutionFailover(List jobExecutionList) +-void handleRerunJobExecution(List needRerunJobExecutionList) +} +class ExecutionStatus { ++SUBMITTED_SUCCESS(0, "submitted", "已提交") ++RUNNING_EXECUTION(1, "running", "执行中") ++READY_PAUSE(2, "ready pause", "准备暂停") ++PAUSE(3, "pause", "暂停") ++READY_STOP(4, "ready stop", "准备停止") ++STOP(5, "stop", "停止") ++FAILURE(6, "failure", "失败") ++SUCCESS(7, "success", "成功") ++NEED_FAULT_TOLERANCE(8, "need fault tolerance","需要容错") ++KILL(9, "kill", "强制终止") ++WAITING_THREAD(10, "waiting thread", "等待线程") ++WAITING_SUMMIT(11, "waiting_summit","待提交") ++boolean typeIsSuccess() ++boolean typeIsFailure() ++boolean typeIsFinished() ++boolean typeIsWaitingThread() ++boolean typeIsPause() ++boolean typeIsStop() ++boolean typeIsRunning() ++boolean typeIsCancel() ++static ExecutionStatus of(int status) ++boolean canPause() +} +class TimeoutStrategy { ++RETRY(0, "retry") ++WARN(1, "warn") ++int getCode() ++String getDescription() ++static TimeoutStrategy of(Integer status) ++static TimeoutStrategy of(String strategy) +} +class DqFailureStrategy { ++NONE(0, "none") ++ALERT(1, "alert") ++int getCode() ++String getDescription() ++static DqFailureStrategy of(Integer status) ++static DqFailureStrategy of(String strategy) +} +DataVinesServerException --|> DataVinesException : "继承" +LivyTaskSubmitHelper --> DataVinesException : "捕获并转换" +JobExecutionFailover --> DataVinesException : "处理异常" +JobExecutionFailover --> ExecutionStatus : "状态检查" +JobExecutionFailover --> TimeoutStrategy : "重试策略" +JobExecutionFailover --> DqFailureStrategy : "告警策略" +``` + +**图源** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) +- [JobExecutionFailover.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\failover\JobExecutionFailover.java) +- [DataVinesException.java](file://datavines-common\src\main\java\io\datavines\common\exception\DataVinesException.java) +- [DataVinesServerException.java](file://datavines-core\src\main\java\io\datavines\core\exception\DataVinesServerException.java) +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java) +- [TimeoutStrategy.java](file://datavines-common\src\main\java\io\datavines\common\enums\TimeoutStrategy.java) +- [DqFailureStrategy.java](file://datavines-server\src\main\java\io\datavines\server\enums\DqFailureStrategy.java) + +## LivyTaskSubmitHelper异常捕获机制 + +LivyTaskSubmitHelper组件负责与Livy服务器交互,提交和管理Spark作业。该组件通过Spring的RestTemplate和KerberosRestTemplate实现HTTP通信,并对各种异常情况进行捕获和处理。 + +在postToLivy方法中,组件首先检查Kerberos认证配置,然后根据配置选择适当的RestTemplate进行HTTP POST请求。当请求失败时,会捕获HttpClientErrorException和通用Exception异常,并记录详细的错误信息,包括响应状态、响应头和响应体。 + +对于GET请求,getFromLivy方法同样处理Kerberos认证,并在发生异常时返回null值。deleteByLivy方法在删除会话时,如果遇到ResourceAccessException(通常表示网络连接问题),会记录错误日志;如果遇到RestClientException,则会尝试通过YARN接口删除应用,实现故障转移。 + +该组件通过标准化的异常处理流程,将外部计算框架的异常转换为系统内部可识别的错误状态,为上层组件提供一致的异常处理接口。 + +**本节来源** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) + +## JobExecutionFailover故障转移策略 + +JobExecutionFailover组件实现了分布式环境下的故障转移和重试机制。该组件通过ScheduledExecutorService定期检查需要状态检查的作业执行情况,实现自动化的故障恢复。 + +组件初始化时创建一个固定大小为2的线程池,并安排YarnJobExecutionStatusChecker任务每4秒执行一次。当检测到作业执行失败时,根据作业的执行状态进行不同的处理: + +1. 对于已有Application ID的作业,将其添加到故障转移请求队列中,并更新执行主机信息 +2. 对于没有Application ID但有Application ID标签的作业,尝试从YARN获取Application ID,如果成功则进行与第一种情况相同的处理 +3. 对于无法获取Application ID的作业,将其添加到需要重新运行的作业列表中 + +在YarnJobExecutionStatusChecker的run方法中,组件会检查每个待检查作业的YARN应用状态。当应用状态为FAILURE、KILL或SUCCESS时,会发送相应的执行响应命令,更新作业状态,并从待检查队列中移除该作业。 + +这种分层的故障转移策略确保了系统在节点故障或网络中断等情况下能够自动恢复,提高了系统的可用性和可靠性。 + +**本节来源** +- [JobExecutionFailover.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\failover\JobExecutionFailover.java) + +## 异常信息分级处理 + +DataVines系统实现了多层次的异常信息处理机制,根据异常的性质和严重程度采取不同的处理策略。 + +### 临时性错误的自动恢复 +对于网络中断、资源暂时不足等临时性错误,系统采用自动重试机制。LivyTaskSubmitHelper中的retryLivyGetAppId方法实现了对Application ID获取的重试逻辑,通过设置重试次数和睡眠时间,避免了因短暂网络波动导致的作业失败。 + +### 永久性错误的人工干预 +对于代码错误、配置错误等永久性错误,系统会记录详细的错误信息,并通过通知系统(如钉钉、邮件等)通知相关人员进行人工干预。DqFailureStrategy枚举定义了两种处理策略:NONE(仅记录)和ALERT(告警并阻塞),允许用户根据业务需求选择适当的处理方式。 + +### 异常分类与状态管理 +系统通过ExecutionStatus枚举定义了多种作业执行状态,包括SUBMITTED_SUCCESS、RUNNING_EXECUTION、FAILURE、SUCCESS等。这些状态不仅反映了作业的当前状况,还指导了后续的处理流程。例如,FAILURE状态会触发故障转移机制,而SUCCESS状态则会结束作业执行。 + +TimeoutStrategy枚举定义了任务超时后的处理策略:RETRY(重试)和WARN(警告)。这种灵活的策略配置允许用户根据任务的重要性和特性选择合适的错误处理方式。 + +**本节来源** +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java) +- [TimeoutStrategy.java](file://datavines-common\src\main\java\io\datavines\common\enums\TimeoutStrategy.java) +- [DqFailureStrategy.java](file://datavines-server\src\main\java\io\datavines\server\enums\DqFailureStrategy.java) + +## 具体异常场景分析 + +### 网络中断场景 +当Livy服务器网络中断时,LivyTaskSubmitHelper的postToLivy方法会捕获ResourceAccessException异常。系统首先尝试通过Livy接口删除会话,如果失败则转而使用YARN接口删除应用,实现跨平台的故障转移。同时,JobExecutionFailover组件会检测到作业状态异常,并启动故障转移流程。 + +### 资源不足场景 +当YARN集群资源不足时,作业可能无法获取足够的资源而处于等待状态。系统通过ExecutionStatus的WAITING_THREAD状态来标识这种情况。JobExecutionFailover组件会定期检查作业状态,一旦资源可用,作业将自动恢复执行。如果等待时间超过预设阈值,系统会根据TimeoutStrategy配置决定是否重试或告警。 + +### 代码错误场景 +当提交的Spark作业包含代码错误时,Livy服务器会返回相应的错误信息。LivyTaskSubmitHelper捕获这些错误并记录详细的错误日志。作业状态会被设置为FAILURE,触发DqFailureStrategy定义的告警策略。系统会保存错误日志和堆栈信息,便于开发人员进行问题排查。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Server as "DataVines服务器" +participant Livy as "Livy服务器" +participant YARN as "YARN集群" +Client->>Server : 提交作业请求 +Server->>Livy : POST /batches +alt 网络正常 +Livy-->>Server : 返回会话ID +Server->>Livy : GET /batches/{id} +Livy-->>Server : 返回应用ID +Server->>YARN : 监控应用状态 +YARN-->>Server : 返回应用状态 +Server->>Client : 返回作业结果 +else 网络中断 +Livy--x Server : 连接超时 +Server->>Livy : DELETE /batches/{id} +Livy--x Server : 连接失败 +Server->>YARN : PUT /ws/v1/cluster/apps/{appId}/state +YARN-->>Server : 应用已终止 +Server->>Client : 返回失败信息 +end +``` + +**图源** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) +- [JobExecutionFailover.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\failover\JobExecutionFailover.java) + +## 结论 +DataVines系统的异常处理机制通过LivyTaskSubmitHelper和JobExecutionFailover两个核心组件,实现了对分布式环境中各种异常的全面捕获和处理。系统采用分层的异常处理策略,对临时性错误实现自动恢复,对永久性错误提供人工干预流程。通过标准化的DataVinesException异常体系,将外部计算框架的异常统一转换为内部可识别的错误状态,确保了系统的稳定性和可靠性。这种健壮的异常处理机制是DataVines能够在复杂分布式环境中稳定运行的关键保障。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\346\211\247\350\241\214\344\270\212\344\270\213\346\226\207\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\346\211\247\350\241\214\344\270\212\344\270\213\346\226\207\347\256\241\347\220\206.md" new file mode 100644 index 00000000..24b78065 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\346\211\247\350\241\214\344\270\212\344\270\213\346\226\207\347\256\241\347\220\206.md" @@ -0,0 +1,264 @@ +# 执行上下文管理 + + +**本文档引用的文件** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [CommandContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/CommandContext.java) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java) +- [JobExecutionCache.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/cache/JobExecutionCache.java) +- [JobExecutionContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/cache/JobExecutionContext.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) + + +## 目录 +1. [简介](#简介) +2. [执行上下文管理架构](#执行上下文管理架构) +3. [CommandContext 任务元数据管理](#commandcontext-任务元数据管理) +4. [JobExecutionResponseContext 状态机管理](#jobexecutionresponsecontext-状态机管理) +5. [上下文生命周期管理](#上下文生命周期管理) +6. [故障恢复与持久化策略](#故障恢复与持久化策略) +7. [执行流程时序分析](#执行流程时序分析) + +## 简介 +本文档深入分析 DataVines 系统中 JobExecuteManager 如何实现分布式任务执行上下文的管理。详细说明 CommandContext 如何存储任务的元数据、配置参数和执行环境信息,以及 JobExecutionResponseContext 如何维护任务状态机的转换过程。同时解释上下文对象在 Server 重启后的恢复机制,以及内存缓存与数据库持久化的同步策略。 + +## 执行上下文管理架构 + +```mermaid +graph TD +A[JobExecuteManager] --> B[CommandContext] +A --> C[JobExecutionResponseContext] +A --> D[JobExecutionCache] +D --> E[JobExecutionContext] +E --> F[JobExecutionRequest] +E --> G[JobRunner] +H[JobRunner] --> I[EngineExecutor] +J[JobExecutionResponseProcessor] --> A +K[JobExecutionExecutor] --> A +L[JobExecutionResponseOperator] --> A +``` + +**图表来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L616) + +## CommandContext 任务元数据管理 + +CommandContext 是任务执行命令的上下文容器,负责存储任务的元数据、配置参数和执行环境信息。该对象作为任务执行请求的载体,在分布式系统中传递任务执行指令。 + +```mermaid +classDiagram +class CommandContext { ++CommandCode commandCode ++Long jobExecutionId ++JobExecutionRequest jobExecutionRequest +} +class JobExecutionRequest { ++long jobExecutionId ++String jobExecutionUniqueId ++String executePlatformType ++String engineType ++String tenantCode ++Integer retryTimes ++Integer timeout ++String executeHost ++LocalDateTime startTime ++LocalDateTime endTime ++Integer status +} +CommandContext --> JobExecutionRequest : "包含" +``` + +**图表来源** +- [CommandContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/CommandContext.java#L22-L31) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java#L26-L85) + +### 元数据存储结构 +CommandContext 通过以下方式管理任务元数据: + +1. **任务标识信息**:存储 jobExecutionId 作为任务的唯一标识 +2. **执行平台信息**:记录 executePlatformType 和 executePlatformParameter +3. **引擎配置**:保存 engineType 和 engineParameter +4. **执行环境**:包含 tenantCode、env 等环境变量 +5. **执行控制参数**:管理 retryTimes、timeout、timeoutStrategy 等控制参数 + +当任务被提交时,JobExecuteManager 会创建 CommandContext 对象并将其放入 jobExecutionQueue 队列中等待处理。 + +**代码路径** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L541-L552) + +## JobExecutionResponseContext 状态机管理 + +JobExecutionResponseContext 负责维护任务状态机的转换过程,通过 CommandCode 和 JobExecutionRequest 的组合来跟踪任务的执行状态变化。 + +```mermaid +stateDiagram-v2 +[*] --> WAITING +WAITING --> RUNNING : JOB_EXECUTE_REQUEST +RUNNING --> SUCCESS : JOB_EXECUTE_RESPONSE(status=SUCCESS) +RUNNING --> FAILURE : JOB_EXECUTE_RESPONSE(status=FAILURE) +RUNNING --> CANCELLED : JOB_KILL_REQUEST +FAILURE --> RETRYING : retryTimes > 0 +RETRYING --> RUNNING : JOB_EXECUTE_REQUEST +SUCCESS --> [*] +FAILURE --> [*] +CANCELLED --> [*] +``` + +**图表来源** +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java#L25-L40) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java#L78-L141) + +### 状态转换机制 +JobExecutionResponseContext 通过 JobExecutionResponseOperator 线程监听 responseQueue 队列中的响应消息,根据不同的 CommandCode 执行相应的状态转换逻辑: + +1. **JOB_EXECUTE_ACK**:任务开始执行,更新任务状态为 RUNNING_EXECUTION +2. **JOB_EXECUTE_RESPONSE**:任务执行完成,根据实际状态更新为 SUCCESS 或 FAILURE +3. **超时处理**:通过 HashedWheelTimer 监控任务执行时间,超时则触发 KILL 操作 + +状态转换过程中,系统会更新数据库中的任务状态,并在必要时触发重试机制。 + +**代码路径** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L276-L351) + +## 上下文生命周期管理 + +执行上下文的生命周期管理涉及创建、更新和销毁三个阶段,确保任务执行过程中的状态一致性。 + +```mermaid +flowchart TD +Start([上下文创建]) --> Create["创建 CommandContext"] +Create --> Queue["放入 jobExecutionQueue"] +Queue --> Executor["JobExecutionExecutor 处理"] +Executor --> Execute["executeJobExecution()"] +Execute --> Context["创建 JobExecutionContext"] +Context --> Cache["存入 JobExecutionCache"] +Cache --> Submit["提交 JobRunner 到线程池"] +Submit --> Running["任务执行中"] +Running --> Response["JobExecutionResponseProcessor 接收响应"] +Response --> Operator["JobExecutionResponseOperator 处理响应"] +Operator --> Update["更新任务状态"] +Update --> Check["检查执行结果"] +Check --> |成功| Success["标记为 SUCCESS"] +Check --> |失败| Failure["检查重试次数"] +Failure --> |可重试| Retry["重新创建 CommandContext"] +Failure --> |不可重试| Final["标记为 FAILURE"] +Success --> Cleanup["清理上下文"] +Final --> Cleanup +Cleanup --> End([上下文销毁]) +``` + +**图表来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L177-L213) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L276-L351) + +### 创建过程 +当任务被提交时,系统执行以下创建流程: +1. 调用 addExecuteCommand 方法创建 JobExecutionRequest +2. 构建 CommandContext 对象并设置 JOB_EXECUTE_REQUEST 命令码 +3. 将 CommandContext 放入 jobExecutionQueue 队列 +4. JobExecutionExecutor 线程从队列中取出 CommandContext +5. 调用 executeJobExecution 方法执行任务 +6. 创建 JobExecutionContext 并存入 JobExecutionCache +7. 提交 JobRunner 到线程池执行 + +### 更新过程 +任务执行过程中,上下文通过以下方式更新: +1. 执行开始时发送 JOB_EXECUTE_ACK 响应 +2. 执行完成时发送 JOB_EXECUTE_RESPONSE 响应 +3. 状态更新通过 JobExecutionResponseOperator 处理 +4. 根据执行结果更新数据库中的任务状态 + +### 销毁过程 +上下文销毁发生在以下情况: +1. 任务成功完成,从缓存中移除 +2. 任务失败且无重试机会,清理相关资源 +3. 任务被取消或超时,执行清理操作 +4. Server 关闭时,关闭相关线程池 + +**代码路径** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L177-L213) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L384-L393) + +## 故障恢复与持久化策略 + +系统通过内存缓存与数据库持久化的协同工作,确保在 Server 重启后能够恢复执行上下文。 + +```mermaid +graph TD +A[任务提交] --> B[内存缓存 JobExecutionCache] +B --> C[数据库持久化] +D[Server 重启] --> E[从数据库加载任务状态] +E --> F[重建内存缓存] +F --> G[恢复任务执行] +H[任务执行] --> I[实时更新内存缓存] +I --> J[异步更新数据库] +K[任务完成] --> L[清理内存缓存] +L --> M[最终持久化结果] +``` + +**图表来源** +- [JobExecutionCache.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/cache/JobExecutionCache.java#L23-L48) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L89-L90) + +### 内存缓存机制 +JobExecutionCache 采用单例模式实现,使用 ConcurrentHashMap 存储 JobExecutionContext 对象: + +1. **缓存结构**:以 jobExecutionId 为键,JobExecutionContext 为值的并发哈希映射 +2. **线程安全**:使用 ConcurrentHashMap 确保多线程环境下的安全性 +3. **快速访问**:提供 getById、cache、remove 等方法实现高效的上下文管理 + +### 持久化同步策略 +系统通过以下策略确保内存缓存与数据库的一致性: + +1. **写前持久化**:任务提交前先在数据库中创建记录 +2. **状态实时同步**:任务状态变更时立即更新数据库 +3. **结果最终持久化**:任务完成后持久化最终结果 +4. **异常清理机制**:任务失败时清理中间结果 + +当 Server 重启时,系统会从数据库加载未完成的任务状态,并重建内存中的执行上下文,确保任务能够继续执行或正确处理。 + +**代码路径** +- [JobExecutionCache.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/cache/JobExecutionCache.java#L23-L48) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L384-L393) + +## 执行流程时序分析 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant JobExecuteManager as "JobExecuteManager" +participant JobExecutionExecutor as "JobExecutionExecutor" +participant JobRunner as "JobRunner" +participant EngineExecutor as "EngineExecutor" +participant JobExecutionResponseProcessor as "JobExecutionResponseProcessor" +participant JobExecutionResponseOperator as "JobExecutionResponseOperator" +Client->>JobExecuteManager : submitJob() +JobExecuteManager->>JobExecuteManager : 创建 CommandContext +JobExecuteManager->>JobExecuteManager : 添加到 jobExecutionQueue +JobExecutionExecutor->>JobExecuteManager : 从队列获取 CommandContext +JobExecutionExecutor->>JobExecuteManager : executeJobExecution() +JobExecuteManager->>JobExecuteManager : 创建 JobExecutionContext +JobExecuteManager->>JobExecutionCache : 缓存 JobExecutionContext +JobExecuteManager->>JobRunner : 创建 JobRunner 实例 +JobExecuteManager->>JobRunner : 提交到 jobExecuteService +JobRunner->>EngineExecutor : init() +JobRunner->>EngineExecutor : execute() +EngineExecutor-->>JobRunner : 执行结果 +JobRunner->>JobRunner : 处理执行结果 +JobRunner->>JobExecutionResponseProcessor : 发送响应 +JobExecutionResponseProcessor->>JobExecuteManager : processJobExecutionExecuteResponse() +JobExecuteManager->>JobExecuteManager : 创建 JobExecutionResponseContext +JobExecuteManager->>JobExecuteManager : 添加到 responseQueue +JobExecutionResponseOperator->>JobExecuteManager : 从队列获取响应 +JobExecutionResponseOperator->>JobExecuteManager : 处理响应并更新状态 +JobExecuteManager-->>Client : 返回执行结果 +``` + +**图表来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L143-L174) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L277-L351) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L63-L81) + +该时序图展示了任务从提交到完成的完整执行流程,包括命令的创建与处理、上下文的管理、任务的执行以及状态的更新等关键步骤。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266.md" new file mode 100644 index 00000000..34979c8a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266.md" @@ -0,0 +1,142 @@ +# 状态同步机制 + + +**本文档引用的文件** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java) +- [JobExecuteAckCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteAckCommand.java) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java) +- [JobExecutionContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/cache/JobExecutionContext.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [CommandCode.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/CommandCode.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [状态同步流程](#状态同步流程) +4. [消息结构设计](#消息结构设计) +5. [外部计算框架集成](#外部计算框架集成) +6. [结论](#结论) + +## 简介 +DataVines的分布式状态同步机制是其核心功能之一,确保了Server端与Engine执行器之间的实时通信和状态同步。该机制通过一系列精心设计的命令和回调接口,实现了任务执行上下文的维护、任务状态的实时推送以及命令的确认应答。本文将深入分析这一机制,重点探讨JobExecuteManager如何维护任务执行上下文,Engine执行器如何通过回调接口将任务状态(提交中、运行中、成功、失败)实时推送回Server,以及Command命令的确认应答机制。此外,还将详细分析JobExecuteResponseCommand的消息结构设计,包括执行日志流式传输、进度百分比更新和最终结果持久化等环节,并通过LivyTaskSubmitHelper的实现说明与外部计算框架集成时的状态监听和异常传播机制。 + +## 核心组件 + +DataVines的状态同步机制涉及多个核心组件,这些组件协同工作以确保任务状态的准确同步。主要组件包括JobExecuteManager、JobExecuteResponseCommand、JobExecuteAckCommand、JobExecutionResponseContext、JobExecutionContext、JobExecutionRequest、LivyTaskSubmitHelper、LivyCommandProcess、EngineExecutor和JobRunner。 + +**Section sources** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L617) +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java#L1-L46) +- [JobExecuteAckCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteAckCommand.java#L1-L47) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java#L1-L40) +- [JobExecutionContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/cache/JobExecutionContext.java#L1-L30) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java#L1-L86) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L1-L258) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L1-L30) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L1-L42) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L60-L93) + +## 状态同步流程 + +DataVines的状态同步流程始于Server端的JobExecuteManager,它负责维护所有任务的执行上下文。当一个任务被提交时,JobExecuteManager会创建一个JobExecutionContext,并将其存储在JobExecutionCache中。这个上下文包含了任务的所有必要信息,如任务ID、执行平台类型、引擎类型、执行参数等。 + +```mermaid +sequenceDiagram +participant Server as "Server端" +participant JobExecuteManager as "JobExecuteManager" +participant JobRunner as "JobRunner" +participant EngineExecutor as "Engine执行器" +Server->>JobExecuteManager : 提交任务执行请求 +JobExecuteManager->>JobExecuteManager : 创建JobExecutionContext +JobExecuteManager->>JobExecutionCache : 缓存执行上下文 +JobExecuteManager->>JobRunner : 提交任务到线程池 +JobRunner->>EngineExecutor : 初始化执行器 +EngineExecutor->>EngineExecutor : 执行任务 +EngineExecutor->>JobRunner : 返回执行结果 +JobRunner->>JobExecuteManager : 发送状态更新 +JobExecuteManager->>JobExecutionCache : 更新执行上下文 +``` + +**Diagram sources** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L178-L214) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L65-L80) + +Engine执行器通过实现EngineExecutor接口来执行任务。在执行过程中,执行器会通过回调接口将任务状态实时推送回Server。这些状态包括提交中、运行中、成功和失败。状态更新通过JobExecuteResponseCommand和JobExecuteAckCommand两种命令实现。JobExecuteAckCommand用于确认任务已成功提交,而JobExecuteResponseCommand则用于报告任务的最终执行结果。 + +**Section sources** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L294-L347) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L70-L93) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L29-L42) + +## 消息结构设计 + +JobExecuteResponseCommand是状态同步机制中的关键消息类型,其设计旨在高效地传输任务执行结果。该命令包含多个字段,如jobExecutionId、status、endTime、applicationIds和processId,这些字段共同描述了任务的执行状态和结果。 + +```mermaid +classDiagram +class JobExecuteResponseCommand { ++long jobExecutionId ++int status ++LocalDateTime endTime ++String applicationIds ++int processId ++JobExecuteResponseCommand() ++JobExecuteResponseCommand(long jobExecutionId) +} +JobExecuteResponseCommand --> BaseCommand : "继承" +``` + +**Diagram sources** +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java#L1-L46) +- [BaseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java#L1-L32) + +执行日志的流式传输通过JobExecutionResponseContext实现,该上下文包含了命令代码和任务执行请求。进度百分比的更新则通过定期发送JobExecuteResponseCommand来实现,每次更新都包含最新的进度信息。最终结果的持久化则在任务完成后,通过将执行结果写入数据库来完成。 + +**Section sources** +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java#L1-L46) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java#L1-L40) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L448-L464) + +## 外部计算框架集成 + +与外部计算框架(如Livy)的集成通过LivyTaskSubmitHelper实现。该辅助类负责与Livy服务器通信,提交任务并监听状态变化。LivyTaskSubmitHelper通过REST API与Livy服务器交互,提交任务后会定期轮询任务状态,直到任务完成或失败。 + +```mermaid +sequenceDiagram +participant EngineExecutor as "Engine执行器" +participant LivyCommandProcess as "LivyCommandProcess" +participant LivyTaskSubmitHelper as "LivyTaskSubmitHelper" +participant LivyServer as "Livy服务器" +EngineExecutor->>LivyCommandProcess : 提交任务 +LivyCommandProcess->>LivyTaskSubmitHelper : 调用postToLivy +LivyTaskSubmitHelper->>LivyServer : POST请求提交任务 +LivyServer-->>LivyTaskSubmitHelper : 返回任务ID +LivyTaskSubmitHelper->>LivyCommandProcess : 返回结果 +LivyCommandProcess->>LivyTaskSubmitHelper : 调用getResultByLivyId +LivyTaskSubmitHelper->>LivyServer : GET请求获取状态 +LivyServer-->>LivyTaskSubmitHelper : 返回状态信息 +LivyTaskSubmitHelper->>LivyCommandProcess : 返回状态 +LivyCommandProcess->>EngineExecutor : 更新执行结果 +``` + +**Diagram sources** +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L1-L30) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L1-L258) + +异常传播机制通过捕获和处理各种异常来实现。例如,当与Livy服务器的通信失败时,LivyTaskSubmitHelper会捕获HttpClientErrorException并记录错误日志。如果任务提交失败,Engine执行器会将任务状态设置为失败,并通过JobExecuteResponseCommand通知Server端。 + +**Section sources** +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L134-L140) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L62-L75) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L80-L93) + +## 结论 + +DataVines的分布式状态同步机制通过精心设计的组件和流程,实现了Server端与Engine执行器之间的高效通信和状态同步。JobExecuteManager通过维护任务执行上下文,确保了任务状态的准确跟踪。Engine执行器通过回调接口实时推送任务状态,保证了状态的及时更新。JobExecuteResponseCommand的消息结构设计合理,支持执行日志流式传输、进度百分比更新和最终结果持久化。通过LivyTaskSubmitHelper的实现,DataVines能够与外部计算框架无缝集成,实现了状态监听和异常传播。这一机制为DataVines的可靠性和可扩展性提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\347\212\266\346\200\201\346\266\210\346\201\257\351\200\232\344\277\241.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\347\212\266\346\200\201\346\266\210\346\201\257\351\200\232\344\277\241.md" new file mode 100644 index 00000000..1a42a51d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\212\266\346\200\201\345\220\214\346\255\245\346\234\272\345\210\266/\347\212\266\346\200\201\346\266\210\346\201\257\351\200\232\344\277\241.md" @@ -0,0 +1,329 @@ +# 状态消息通信 + + +**本文档引用的文件** +- [JobExecuteResponseCommand.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\JobExecuteResponseCommand.java) +- [JobExecuteAckCommand.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\JobExecuteAckCommand.java) +- [CommandCode.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\CommandCode.java) +- [AbstractEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractEngineExecutor.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [JobExecutionRequest.java](file://datavines-common\src\main\java\io\datavines\common\entity\JobExecutionRequest.java) +- [JSONUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\JSONUtils.java) +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java) + + +## 目录 +1. [引言](#引言) +2. [消息通信机制概述](#消息通信机制概述) +3. [消息设计原理](#消息设计原理) +4. [状态上报接口实现](#状态上报接口实现) +5. [消息处理机制](#消息处理机制) +6. [通信序列图](#通信序列图) +7. [总结](#总结) + +## 引言 +本文档详细解析DataVines系统中状态同步的消息通信机制。重点阐述JobExecuteResponseCommand和JobExecuteAckCommand的设计原理,包括消息序列化格式、版本控制和校验机制。同时说明Engine执行器如何通过AbstractEngineExecutor基类实现标准化的状态上报接口,以及Server端如何处理乱序消息和重复消息。 + +## 消息通信机制概述 +DataVines系统采用基于命令模式的消息通信机制来实现Engine执行器与Server之间的状态同步。该机制通过定义不同类型的消息命令,实现任务执行过程中的状态上报、确认和结果反馈。 + +系统中的消息通信主要涉及以下核心组件: +- **JobExecuteAckCommand**: 任务执行确认命令,用于Engine向Server上报任务开始执行的状态 +- **JobExecuteResponseCommand**: 任务执行响应命令,用于Engine向Server上报任务执行完成的结果 +- **CommandCode**: 命令代码枚举,定义了系统中所有支持的命令类型 +- **JobExecuteManager**: 任务执行管理器,负责处理来自Engine的各种命令 + +消息通信采用JSON格式进行序列化,通过统一的通信通道进行传输,确保了消息的可读性和跨平台兼容性。 + +## 消息设计原理 + +### 消息序列化格式 +系统采用JSON格式作为消息的序列化格式,主要基于以下考虑: + +1. **可读性强**: JSON格式具有良好的可读性,便于调试和问题排查 +2. **跨平台兼容**: JSON是广泛支持的数据交换格式,确保了不同语言实现的组件之间的兼容性 +3. **灵活性高**: JSON格式支持嵌套结构,能够灵活表达复杂的数据结构 + +消息序列化由JSONUtils工具类统一处理,该类基于Jackson库实现,配置了以下特性: +- 忽略未知属性(FAIL_ON_UNKNOWN_PROPERTIES为false) +- 支持空数组和空字符串作为null值处理 +- 支持Java 8时间类型(LocalDateTime)的序列化 +- 日期格式统一为"yyyy-MM-dd HH:mm:ss" +- 空值字段不进行序列化(NON_NULL) + +```mermaid +classDiagram +class BaseCommand { ++CommandCode commandCode ++CommandCode getCommandCode() ++void setCommandCode(CommandCode) +} +class JobExecuteAckCommand { ++long jobExecutionId ++LocalDateTime startTime ++String host ++int status ++String logPath ++String executePath ++JobExecuteAckCommand(long) ++JobExecuteAckCommand() +} +class JobExecuteResponseCommand { ++long jobExecutionId ++int status ++LocalDateTime endTime ++String applicationIds ++int processId ++JobExecuteResponseCommand() ++JobExecuteResponseCommand(long) +} +class CommandCode { ++DEFAULT ++JOB_EXECUTE_REQUEST ++JOB_EXECUTE_ACK ++JOB_EXECUTE_RESPONSE ++JOB_KILL_REQUEST ++JOB_KILL_RESPONSE +} +BaseCommand <|-- JobExecuteAckCommand +BaseCommand <|-- JobExecuteResponseCommand +JobExecuteAckCommand --> CommandCode : "commandCode = JOB_EXECUTE_ACK" +JobExecuteResponseCommand --> CommandCode : "commandCode = JOB_EXECUTE_RESPONSE" +``` + +**图来源** +- [JobExecuteAckCommand.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\JobExecuteAckCommand.java) +- [JobExecuteResponseCommand.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\JobExecuteResponseCommand.java) +- [CommandCode.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\CommandCode.java) + +### 版本控制机制 +系统通过CommandCode枚举实现消息的版本控制。CommandCode定义了所有支持的命令类型,包括: +- JOB_EXECUTE_REQUEST: 任务执行请求 +- JOB_EXECUTE_ACK: 任务执行确认 +- JOB_EXECUTE_RESPONSE: 任务执行响应 +- JOB_KILL_REQUEST: 任务终止请求 +- JOB_KILL_RESPONSE: 任务终止响应 + +这种设计允许系统在不影响现有功能的情况下扩展新的命令类型。当新增命令时,只需在CommandCode中添加新的枚举值,而不会影响已有的消息处理逻辑。 + +### 校验机制 +消息校验主要通过以下机制实现: + +1. **状态码校验**: 使用ExecutionStatus枚举确保状态值的有效性 +2. **必填字段校验**: 关键字段如jobExecutionId不能为空 +3. **时间顺序校验**: 确保startTime早于endTime +4. **状态转换校验**: 验证状态转换的合法性(如不能从"成功"状态转换为"执行中") + +ExecutionStatus枚举定义了系统中所有可能的任务状态,包括: +- SUBMITTED_SUCCESS: 已提交 +- RUNNING_EXECUTION: 执行中 +- SUCCESS: 成功 +- FAILURE: 失败 +- KILL: 强制终止 + +每个状态都有对应的code、description和zhDescription,便于国际化支持。 + +**本节来源** +- [JobExecuteAckCommand.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\JobExecuteAckCommand.java#L26-L36) +- [JobExecuteResponseCommand.java](file://datavines-server\src\main\java\io\datavines\server\dqc\command\JobExecuteResponseCommand.java#L26-L34) +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java#L45-L56) + +## 状态上报接口实现 + +### AbstractEngineExecutor基类 +Engine执行器通过继承AbstractEngineExecutor基类实现标准化的状态上报接口。该基类提供了统一的状态上报机制,确保所有Engine实现遵循相同的消息通信规范。 + +```mermaid +classDiagram +class AbstractEngineExecutor { +-JobExecutionRequest jobExecutionRequest +-Logger logger +-volatile boolean cancel +-ProcessResult processResult ++void logHandle(List) ++boolean isCancel() ++abstract String buildCommand() +} +class EngineExecutor { +<> ++boolean isCancel() +} +class JobExecutionRequest { ++long jobExecutionId ++String jobExecutionUniqueId ++String jobExecutionName ++String executePlatformType ++String engineType ++String engineParameter ++String executeHost ++int status ++String applicationId ++int processId ++String executeFilePath ++String logPath ++LocalDateTime startTime ++LocalDateTime endTime +} +EngineExecutor <|-- AbstractEngineExecutor +AbstractEngineExecutor --> JobExecutionRequest : "持有" +``` + +**图来源** +- [AbstractEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractEngineExecutor.java) +- [JobExecutionRequest.java](file://datavines-common\src\main\java\io\datavines\common\entity\JobExecutionRequest.java) + +### 核心功能 +AbstractEngineExecutor基类提供了以下核心功能: + +1. **状态管理**: 通过jobExecutionRequest对象管理任务执行状态 +2. **日志处理**: 提供logHandle方法统一处理执行日志 +3. **取消检测**: isCancel方法用于检测任务是否被取消 +4. **命令构建**: buildCommand抽象方法由子类实现,用于构建具体的执行命令 + +### 状态上报流程 +Engine执行器的状态上报流程如下: + +1. 任务开始执行时,创建JobExecuteAckCommand对象,设置开始时间、执行主机等信息 +2. 通过通信通道发送JOB_EXECUTE_ACK命令到Server +3. 任务执行完成后,创建JobExecuteResponseCommand对象,设置结束时间、执行状态、应用ID等信息 +4. 通过通信通道发送JOB_EXECUTE_RESPONSE命令到Server + +这种分阶段上报的机制确保了Server能够实时跟踪任务的执行状态,及时发现和处理异常情况。 + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractEngineExecutor.java#L27-L55) +- [JobExecutionRequest.java](file://datavines-common\src\main\java\io\datavines\common\entity\JobExecutionRequest.java#L28-L84) + +## 消息处理机制 + +### 乱序消息处理 +Server端通过以下机制处理乱序消息: + +1. **消息队列**: 使用阻塞队列(jobExecutionQueue)缓存接收到的消息,确保消息按顺序处理 +2. **状态机验证**: 根据ExecutionStatus的状态转换规则验证消息的合理性 +3. **时间戳校验**: 比较消息中的时间戳,确保逻辑顺序的正确性 + +当接收到JOB_EXECUTE_ACK消息时,系统会更新任务的开始时间、执行主机等信息;当接收到JOB_EXECUTE_RESPONSE消息时,系统会更新任务的结束时间、执行状态等信息。 + +### 重复消息处理 +系统通过以下机制处理重复消息: + +1. **幂等性设计**: 消息处理逻辑设计为幂等操作,重复处理相同消息不会产生副作用 +2. **状态检查**: 在处理消息前检查任务的当前状态,避免状态回退 +3. **唯一标识**: 使用jobExecutionId作为消息的唯一标识,避免重复处理 + +```mermaid +flowchart TD +A[接收消息] --> B{消息类型} +B --> |JOB_EXECUTE_ACK| C[处理执行确认] +B --> |JOB_EXECUTE_RESPONSE| D[处理执行响应] +C --> E[更新任务开始时间] +C --> F[更新执行主机] +C --> G[更新日志路径] +D --> H[更新任务结束时间] +D --> I[更新执行状态] +D --> J[更新应用ID] +E --> K[持久化到数据库] +F --> K +G --> K +H --> K +I --> K +J --> K +K --> L[通知监听器] +``` + +**图来源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L294-L304) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L448-L464) + +### 消息处理流程 +Server端的消息处理流程如下: + +1. 接收来自Engine的消息 +2. 根据commandCode判断消息类型 +3. 对于JOB_EXECUTE_ACK消息: + - 更新任务的开始时间 + - 更新执行状态为"执行中" + - 更新执行文件路径和日志路径 + - 更新执行主机信息 + - 持久化到数据库 +4. 对于JOB_EXECUTE_RESPONSE消息: + - 更新任务的结束时间 + - 更新执行状态 + - 更新应用ID + - 更新进程ID + - 持久化到数据库 + +**本节来源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java#L294-L464) + +## 通信序列图 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Server as "Server" +participant Engine as "Engine执行器" +Client->>Server : 提交任务 +Server->>Server : 创建JobExecution记录 +Server->>Engine : 发送JOB_EXECUTE_REQUEST +Engine->>Engine : 开始执行任务 +Engine->>Server : 发送JOB_EXECUTE_ACK +Server->>Server : 更新任务状态为"执行中" +Server-->>Client : 返回任务提交成功 +Engine->>Engine : 执行任务逻辑 +Engine->>Engine : 任务执行完成 +Engine->>Server : 发送JOB_EXECUTE_RESPONSE +Server->>Server : 更新任务状态为"成功"或"失败" +Server->>Server : 记录执行结果 +Server-->>Client : 通知任务完成 +``` + +**图来源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [AbstractEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractEngineExecutor.java) + +### 完整消息交互流程 +从任务提交到完成的完整消息交互流程如下: + +1. **任务提交阶段**: + - 客户端向Server提交任务 + - Server创建JobExecution记录,状态为"已提交" + - Server向Engine发送JOB_EXECUTE_REQUEST命令 + +2. **任务执行确认阶段**: + - Engine收到执行请求,开始执行任务 + - Engine创建JobExecuteAckCommand,包含开始时间、执行主机等信息 + - Engine向Server发送JOB_EXECUTE_ACK命令 + - Server更新任务状态为"执行中",记录开始时间和执行主机 + +3. **任务执行阶段**: + - Engine执行具体的任务逻辑 + - 执行过程中可能产生日志,通过其他机制上报 + +4. **任务完成阶段**: + - Engine完成任务执行,创建JobExecuteResponseCommand + - JobExecuteResponseCommand包含结束时间、执行状态、应用ID等信息 + - Engine向Server发送JOB_EXECUTE_RESPONSE命令 + - Server更新任务状态为"成功"或"失败",记录执行结果 + +5. **结果通知阶段**: + - Server向客户端通知任务完成 + - 客户端可以查询详细的执行结果 + +这种分阶段的状态上报机制确保了任务执行过程的可追溯性,即使在Engine或Server发生故障的情况下,也能通过状态信息进行故障排查和恢复。 + +**本节来源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [AbstractEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractEngineExecutor.java) + +## 总结 +DataVines系统的状态同步消息通信机制设计合理,具有以下特点: + +1. **清晰的命令划分**: 通过JobExecuteAckCommand和JobExecuteResponseCommand分别处理任务执行确认和结果反馈,职责分明 +2. **标准化的接口**: AbstractEngineExecutor基类提供了统一的状态上报接口,确保了不同Engine实现的一致性 +3. **健壮的消息处理**: Server端能够有效处理乱序和重复消息,保证了系统的稳定性 +4. **完善的序列化机制**: 基于JSON的序列化格式,配合JSONUtils工具类,确保了消息的可读性和兼容性 +5. **严格的状态管理**: 通过ExecutionStatus枚举和状态转换规则,确保了任务状态的正确性 + +该机制为DataVines系统提供了可靠的状态同步能力,是系统稳定运行的重要保障。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217.md" new file mode 100644 index 00000000..cb62d03d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217/\347\273\204\344\273\266\344\272\244\344\272\222\346\250\241\345\274\217.md" @@ -0,0 +1,240 @@ +# 组件交互模式 + + +**本文档引用的文件** +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [JobRunner.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/runner/JobRunner.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java) +- [JobExecutionResponseProcessor.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件交互流程](#核心组件交互流程) +3. [命令模式与任务封装](#命令模式与任务封装) +4. [参数序列化协议](#参数序列化协议) +5. [引擎执行器调用链](#引擎执行器调用链) +6. [连接器数据源交互](#连接器数据源交互) +7. [异步回调与状态更新](#异步回调与状态更新) +8. [松耦合架构优势](#松耦合架构优势) +9. [结论](#结论) + +## 引言 + +DataVines是一个数据质量监控系统,其核心架构采用松耦合的组件交互模式。当用户提交质量检查任务后,系统通过一系列精心设计的组件协作完成任务的执行与结果反馈。本文档深入分析从用户提交任务开始,Server如何通过命令模式将任务参数封装并传递给Engine执行器,Engine如何调用Connector进行数据源连接和SQL执行,以及结果如何通过回调机制返回Server进行持久化。重点解析基于JSON的参数序列化协议、RESTful API通信机制和异步任务状态更新流程。 + +## 核心组件交互流程 + +DataVines的核心交互流程始于用户提交质量检查任务。Server接收到任务后,首先通过`DataQualityJobParameterBuilder`构建`JobExecutionParameter`对象,该对象封装了任务所需的所有参数,包括数据源连接信息和质量检查指标参数。随后,Server将这些参数序列化为JSON格式,并通过`JobExecutionRequest`对象封装执行平台、引擎类型、超时策略等执行上下文信息。 + +```mermaid +sequenceDiagram +participant 用户 as "用户" +participant Server as "Server" +participant Engine as "EngineExecutor" +participant Connector as "Connector" +用户->>Server : 提交质量检查任务 +Server->>Server : 构建JobExecutionParameter +Server->>Server : 序列化为JSON +Server->>Engine : 通过命令模式传递JobExecutionRequest +Engine->>Engine : 初始化执行环境 +Engine->>Connector : 调用executeQuery执行SQL +Connector->>数据源 : 执行SQL查询 +数据源-->>Connector : 返回查询结果 +Connector-->>Engine : 返回执行结果 +Engine-->>Server : 通过回调机制返回ProcessResult +Server->>Server : 持久化执行结果 +Server-->>用户 : 返回任务执行状态 +``` + +**图示来源** +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) + +## 命令模式与任务封装 + +DataVines系统采用命令模式(Command Pattern)来封装和传递质量检查任务。`JobExecutionRequest`类作为命令对象,封装了任务执行所需的所有信息,包括任务ID、执行平台类型、引擎类型、超时时间、重试次数等。这种设计模式将请求封装为对象,使得可以用不同的请求对客户进行参数化。 + +Server通过`JobExecuteManager`管理任务队列,将`JobExecutionRequest`放入`jobExecutionQueue`中等待处理。`JobExecutionExecutor`作为命令执行者,从队列中取出命令并执行。这种解耦设计使得请求的发送者(Server)和接收者(EngineExecutor)之间无需直接耦合,提高了系统的灵活性和可扩展性。 + +```mermaid +classDiagram +class JobExecutionRequest { ++long id ++long jobExecutionId ++String jobExecutionUniqueId ++String executePlatformType ++String engineType ++int timeout ++int retryTimes ++Integer status ++LocalDateTime startTime ++LocalDateTime endTime +} +class JobExecuteManager { +-LinkedBlockingQueue jobExecutionQueue +-ConcurrentHashMap unFinishedJobExecutionMap +-ExecutorService executorService ++start() ++addKillCommand(Long jobExecutionId) ++processJobExecutionExecuteResponse(JobExecuteResponseCommand) +} +class JobExecutionExecutor { ++run() +} +JobExecuteManager --> JobExecutionExecutor : "创建并提交" +JobExecuteManager --> JobExecutionRequest : "包含" +JobExecutionExecutor --> JobExecutionRequest : "处理" +``` + +**图示来源** +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) + +## 参数序列化协议 + +DataVines系统采用JSON作为参数序列化协议,实现了跨平台、跨语言的数据交换。`JSONUtils`工具类提供了完整的JSON序列化和反序列化功能,支持对象到JSON字符串的转换、JSON字符串到对象的解析、JSON数组和映射的处理等。 + +`JobExecutionParameter`对象通过`JSONUtils.toJsonString()`方法序列化为JSON字符串,然后作为`applicationParameter`字段嵌入到`JobExecutionRequest`中。在Engine端,通过`JSONUtils.parseObject()`方法将JSON字符串反序列化为`JobExecutionParameter`对象,从而恢复完整的任务参数。 + +```mermaid +flowchart TD +Start([开始]) --> BuildParameter["构建JobExecutionParameter对象"] +BuildParameter --> Serialize["调用JSONUtils.toJsonString()"] +Serialize --> GetJSON["获取JSON字符串"] +GetJSON --> SetParameter["设置到JobExecutionRequest.applicationParameter"] +SetParameter --> Transfer["传输到Engine"] +Transfer --> Deserialize["调用JSONUtils.parseObject()"] +Deserialize --> Restore["恢复JobExecutionParameter对象"] +Restore --> Execute["执行质量检查任务"] +Execute --> End([结束]) +``` + +**图示来源** +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) + +## 引擎执行器调用链 + +Engine执行器的调用链遵循标准的执行生命周期:初始化(init)、执行(execute)、后续处理(after)和取消(cancel)。`EngineExecutor`接口定义了这一生命周期,所有具体的执行器实现都必须遵循此契约。 + +当`JobRunner`接收到`JobExecutionRequest`后,通过SPI机制加载对应的`EngineExecutor`实现。调用链从`init()`方法开始,设置执行上下文;然后调用`execute()`方法执行实际的任务;任务完成后调用`after()`方法进行清理;如果任务被取消,则调用`cancel()`方法。 + +```mermaid +sequenceDiagram +participant JobRunner as "JobRunner" +participant EngineExecutor as "EngineExecutor" +participant Bootstrap as "Bootstrap" +JobRunner->>EngineExecutor : getNewPlugin(engineType) +JobRunner->>EngineExecutor : init(jobExecutionRequest, logger, configurations) +JobRunner->>EngineExecutor : execute() +EngineExecutor->>Bootstrap : execute(args) +Bootstrap-->>EngineExecutor : 返回ProcessResult +EngineExecutor-->>JobRunner : getProcessResult() +JobRunner->>EngineExecutor : after() +``` + +**图示来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [JobRunner.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/runner/JobRunner.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) + +## 连接器数据源交互 + +Connector组件负责与各种数据源进行交互,实现了统一的数据访问接口。`Connector`接口定义了获取数据库、表、列等元数据的方法,以及执行SQL查询的核心功能。`Executor`接口则专门负责SQL执行,通过`queryForPage`、`queryForList`等方法提供分页查询和列表查询功能。 + +`BaseJdbcExecutor`作为JDBC连接器的基类,实现了通用的SQL执行逻辑。它通过`JdbcTemplate`与数据库交互,使用`SqlUtils.query()`方法执行SQL并返回带有列信息的结果集。这种设计使得不同数据库的连接器可以共享大部分代码,只需实现特定的方言和配置即可。 + +```mermaid +classDiagram +class Connector { ++getDatabases(GetDatabasesRequestParam) ++getTables(GetTablesRequestParam) ++getColumns(GetColumnsRequestParam) ++testConnect(TestConnectionRequestParam) ++keyProperties() +} +class Executor { ++queryForPage(ExecuteRequestParam) ++queryForList(ExecuteRequestParam) ++queryForOne(ExecuteRequestParam) ++deleteData(ExecuteRequestParam) +} +class BaseJdbcExecutor { +-DataSourceClient dataSourceClient ++query(JdbcTemplate, String, int) ++queryForPage(ExecuteRequestParam) +} +class JdbcConnector { ++getDatabases() ++getTables() ++getColumns() ++testConnect() +} +Connector <|.. JdbcConnector : "实现" +Executor <|.. BaseJdbcExecutor : "实现" +BaseJdbcExecutor --> JdbcTemplate : "使用" +SqlUtils --> BaseJdbcExecutor : "提供" +``` + +**图示来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +## 异步回调与状态更新 + +DataVines系统采用异步回调机制处理任务执行结果,实现了非阻塞的任务处理流程。`JobExecutionResponseProcessor`作为回调处理器,接收来自Engine的执行结果,并通过`JobExecuteManager`更新任务状态。 + +当Engine完成任务执行后,会创建`JobExecuteResponseCommand`对象,包含任务ID、状态码、结束时间等信息。该命令被放入`responseQueue`队列中,由`JobExecutionResponseOperator`线程消费。操作符根据命令类型更新数据库中的任务状态,并清理相关缓存。 + +```mermaid +sequenceDiagram +participant Engine as "Engine" +participant ResponseProcessor as "JobExecutionResponseProcessor" +participant Manager as "JobExecuteManager" +participant Operator as "JobExecutionResponseOperator" +participant Database as "数据库" +Engine->>ResponseProcessor : processJobExecutionExecuteResponse() +ResponseProcessor->>Manager : processJobExecutionExecuteResponse() +Manager->>Manager : 创建JobExecutionResponseContext +Manager->>Manager : 放入responseQueue +loop 持续消费 +Operator->>Manager : take()从队列获取 +alt 状态为成功 +Manager->>Database : 更新任务状态为SUCCESS +else 状态为失败 +Manager->>Database : 更新任务状态为FAILURE +end +Manager->>Manager : 清理缓存 +end +``` + +**图示来源** +- [JobExecutionResponseProcessor.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java) + +## 松耦合架构优势 + +DataVines的松耦合交互模式带来了显著的扩展性和容错性优势。通过命令模式和JSON序列化协议,Server与Engine之间实现了完全的解耦,使得可以独立开发和部署不同版本的组件。SPI机制允许动态加载执行器和连接器,无需修改核心代码即可支持新的计算引擎和数据源。 + +异步回调机制提高了系统的响应性和可靠性。即使某个任务执行失败,也不会阻塞其他任务的处理。`JobExecuteManager`中的超时定时器(`HashedWheelTimer`)能够自动处理长时间运行的任务,防止资源泄漏。任务状态的持久化确保了系统重启后能够恢复执行上下文,提高了系统的容错能力。 + +此外,基于接口的编程和依赖注入使得组件易于测试和替换。`EngineExecutor`和`Connector`的接口定义了清晰的契约,任何符合契约的实现都可以无缝集成到系统中。这种设计模式为系统的长期演进和维护提供了坚实的基础。 + +## 结论 + +DataVines通过精心设计的组件交互模式,实现了高效、可靠的数据质量检查功能。从用户提交任务开始,系统通过命令模式封装任务参数,利用JSON协议进行序列化,通过Engine执行器调用链执行任务,借助Connector与数据源交互,并通过异步回调机制更新任务状态。这种松耦合架构不仅提高了系统的扩展性和容错性,还为未来的功能演进提供了灵活的基础。深入理解这一交互模式,对于优化系统性能、排查问题和开发新功能都具有重要意义。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/Connector\347\273\204\344\273\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/Connector\347\273\204\344\273\266.md" new file mode 100644 index 00000000..50da954a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/Connector\347\273\204\344\273\266.md" @@ -0,0 +1,732 @@ +# Connector组件 + + +**本文档中引用的文件** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java) +- [MysqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnectorFactory.java) +- [PostgreSqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnectorFactory.java) +- [MysqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDialect.java) +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) + + +## 目录 +1. [引言](#引言) +2. [插件化架构设计](#插件化架构设计) +3. [核心接口与职责](#核心接口与职责) +4. [JDBC通用连接实现](#jdbc通用连接实现) +5. [具体数据源插件实现](#具体数据源插件实现) +6. [SPI插件发现机制](#spi插件发现机制) +7. [连接池与连接管理](#连接池与连接管理) +8. [SQL执行与结果处理](#sql执行与结果处理) +9. [跨数据库方言兼容性](#跨数据库方言兼容性) +10. [安全与防护机制](#安全与防护机制) +11. [扩展新数据源连接器](#扩展新数据源连接器) +12. [总结](#总结) + +## 引言 + +DataVines Connector组件采用插件化设计,为大数据质量监控系统提供了灵活、可扩展的数据源连接能力。该组件通过定义清晰的接口契约和SPI(Service Provider Interface)机制,实现了对20多种数据源的统一管理和动态加载。本文将深入剖析Connector组件的架构设计,重点分析其插件化机制、JDBC通用连接逻辑以及MySQL、PostgreSQL等具体数据源的实现方式。 + +## 插件化架构设计 + +DataVines Connector的插件化架构基于SPI机制构建,通过分层设计实现了功能解耦和灵活扩展。整个架构分为核心API层、JDBC通用实现层和具体数据源插件层。 + +```mermaid +graph TD +subgraph "核心API层" +Connector[Connector接口] +ConnectorFactory[ConnectorFactory接口] +Dialect[Dialect接口] +Executor[Executor接口] +DataSourceClient[DataSourceClient接口] +end +subgraph "JDBC通用实现层" +JdbcConnector[JdbcConnector抽象类] +BaseJdbcExecutor[BaseJdbcExecutor抽象类] +JdbcDataSourceClient[JdbcDataSourceClient] +JdbcDialect[JdbcDialect抽象类] +AbstractJdbcConnectorFactory[AbstractJdbcConnectorFactory] +end +subgraph "具体数据源插件层" +MysqlPlugin[MySQL插件] +PostgresqlPlugin[PostgreSQL插件] +OraclePlugin[Oracle插件] +HivePlugin[Hive插件] +ClickHousePlugin[ClickHouse插件] +end +ConnectorFactory --> Connector +ConnectorFactory --> Dialect +ConnectorFactory --> Executor +ConnectorFactory --> DataSourceClient +JdbcConnector --> Connector +BaseJdbcExecutor --> Executor +JdbcDataSourceClient --> DataSourceClient +JdbcDialect --> Dialect +AbstractJdbcConnectorFactory --> ConnectorFactory +MysqlPlugin --> JdbcConnector +MysqlPlugin --> BaseJdbcExecutor +MysqlPlugin --> JdbcDataSourceClient +MysqlPlugin --> JdbcDialect +MysqlPlugin --> AbstractJdbcConnectorFactory +PostgresqlPlugin --> JdbcConnector +PostgresqlPlugin --> BaseJdbcExecutor +PostgresqlPlugin --> JdbcDataSourceClient +PostgresqlPlugin --> JdbcDialect +PostgresqlPlugin --> AbstractJdbcConnectorFactory +OraclePlugin --> JdbcConnector +OraclePlugin --> BaseJdbcExecutor +OraclePlugin --> JdbcDataSourceClient +OraclePlugin --> JdbcDialect +OraclePlugin --> AbstractJdbcConnectorFactory +HivePlugin --> JdbcConnector +HivePlugin --> BaseJdbcExecutor +HivePlugin --> JdbcDataSourceClient +HivePlugin --> JdbcDialect +HivePlugin --> AbstractJdbcConnectorFactory +ClickHousePlugin --> JdbcConnector +ClickHousePlugin --> BaseJdbcExecutor +ClickHousePlugin --> JdbcDataSourceClient +ClickHousePlugin --> JdbcDialect +ClickHousePlugin --> AbstractJdbcConnectorFactory +``` + +**图示来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +**本节来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +## 核心接口与职责 + +Connector组件定义了一系列核心接口,每个接口都有明确的职责划分,实现了关注点分离的设计原则。 + +### Connector接口 + +`Connector`接口是数据源连接器的核心接口,定义了数据源的基本操作能力: + +```mermaid +classDiagram +class Connector { ++getDatabases(GetDatabasesRequestParam) ConnectorResponse ++getTables(GetTablesRequestParam) ConnectorResponse ++getColumns(GetColumnsRequestParam) ConnectorResponse ++getPartitions(ConnectorRequestParam) ConnectorResponse ++testConnect(TestConnectionRequestParam) ConnectorResponse ++keyProperties() String[] +} +class GetDatabasesRequestParam { ++String dataSourceParam +} +class GetTablesRequestParam { ++String dataSourceParam ++String database +} +class GetColumnsRequestParam { ++String dataSourceParam ++String dataBase ++String table +} +class TestConnectionRequestParam { ++String dataSourceParam +} +class ConnectorResponse { ++Status status ++Object result ++String errorMsg ++static ConnectorResponseBuilder builder() +} +Connector <|-- JdbcConnector : "实现" +GetDatabasesRequestParam --> Connector : "作为参数" +GetTablesRequestParam --> Connector : "作为参数" +GetColumnsRequestParam --> Connector : "作为参数" +TestConnectionRequestParam --> Connector : "作为参数" +ConnectorResponse <-- Connector : "返回类型" +``` + +**图示来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) + +**本节来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) + +### ConnectorFactory接口 + +`ConnectorFactory`接口是插件工厂接口,通过SPI注解标记,用于创建和管理连接器实例: + +```mermaid +classDiagram +class ConnectorFactory { ++getCategory() String ++getConnector() Connector ++getResponseConverter() ResponseConverter ++getDialect() Dialect ++getConnectorParameterConverter() ParameterConverter ++getExecutor() Executor ++getTypeConverter() TypeConverter ++getConfigBuilder() ConfigBuilder ++getDataSourceClient() DataSourceClient ++getStatementSplitter() StatementSplitter ++getStatementParser() StatementParser ++getMetricScript() MetricScript ++showInFrontend() Boolean +} +class SPI { ++String value() +} +ConnectorFactory <|-- AbstractJdbcConnectorFactory : "实现" +ConnectorFactory <|-- MysqlConnectorFactory : "实现" +ConnectorFactory <|-- PostgreSqlConnectorFactory : "实现" +SPI <-- ConnectorFactory : "注解" +``` + +**图示来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +**本节来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +### Dialect接口 + +`Dialect`接口定义了数据库方言相关的操作,处理不同数据库的SQL语法差异: + +```mermaid +classDiagram +class Dialect { ++getDriver() String ++getColumnPrefix() String ++getColumnSuffix() String ++getDialectKeyMap() Map~String,String~ ++getExcludeDatabases() String[] ++getFullQualifiedTableName(String,String,String,boolean) String ++invalidateItemCanOutput() boolean ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++getJDBCType(DataType) String ++getDataType(String) DataType ++quoteIdentifier(String) String ++getQuoteIdentifier() String ++getTableExistsQuery(String) String ++getSchemaQuery(String) String ++getCountQuery(String) String ++getSelectQuery(String) String ++getCreateTableAsSelectStatement(String,String,String) String ++getCreateTableAsSelectStatementFromSql(String,String,String) String ++getCreateTableStatement(String,StructField[],TypeConverter) String ++getInsertAsSelectStatement(String,String,String) String ++getInsertAsSelectStatementFromSql(String,String,String) String ++getErrorDataScript(Map~String,String~) String ++getValidateResultDataScript(Map~String,String~) String ++getPageFromResultSet(Statement,ResultSet,String,int,int) ResultList +} +class DataType { ++STRING ++INTEGER ++LONG ++FLOAT ++DOUBLE ++BOOLEAN ++TIMESTAMP ++DATE ++DECIMAL +} +class StructField { ++String name ++DataType dataType ++String comment +} +class ResultList { ++Map[]String,Object~~ result ++QueryColumn[] columns +} +Dialect <|-- JdbcDialect : "实现" +Dialect <|-- MysqlDialect : "实现" +Dialect <|-- PostgreSqlDialect : "实现" +DataType <-- Dialect : "使用" +StructField <-- Dialect : "使用" +ResultList <-- Dialect : "使用" +``` + +**图示来源** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) + +**本节来源** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) + +## JDBC通用连接实现 + +JDBC通用连接实现层提供了基于JDBC标准的通用连接逻辑,为各种支持JDBC的数据源提供了基础实现。 + +### JdbcConnector抽象类 + +`JdbcConnector`是所有JDBC数据源连接器的基类,实现了`Connector`接口的核心功能: + +```mermaid +classDiagram +class JdbcConnector { +-Logger logger +-static final String TABLE +-static final String VIEW +-static final String[] TABLE_TYPES +-static final String TABLE_NAME +-static final String TABLE_TYPE +-DataSourceClient dataSourceClient ++JdbcConnector(DataSourceClient) ++getDatabases(GetDatabasesRequestParam) ConnectorResponse ++getTables(GetTablesRequestParam) ConnectorResponse ++getColumns(GetColumnsRequestParam) ConnectorResponse ++getPartitions(ConnectorRequestParam) ConnectorResponse ++testConnect(TestConnectionRequestParam) ConnectorResponse ++keyProperties() String[] ++getMetadataDatabases(Connection) ResultSet ++getMetadataTables(DatabaseMetaData,String,String) ResultSet ++getMetadataColumns(DatabaseMetaData,String,String,String,String) ResultSet ++getPrimaryKeys(DatabaseMetaData,String,String,String) ResultSet +} +class DataSourceClient { ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map~String,Object~) DataSource ++getDataSource(Properties) DataSource ++getConnection(BaseJdbcDataSourceInfo) Connection ++getConnection(Map~String,Object~) Connection ++getConnection(Map~String,Object~,Logger) Connection ++getConnection(Properties) Connection ++getJdbcTemplate(BaseJdbcDataSourceInfo) JdbcTemplate +} +class BaseJdbcDataSourceInfo { ++String host ++int port ++String database ++String user ++String password ++String jdbcUrl ++loadClass() void ++getJdbcUrl() String +} +JdbcConnector <|-- MysqlConnector : "继承" +JdbcConnector <|-- PostgreSqlConnector : "继承" +JdbcConnector <|-- OracleConnector : "继承" +DataSourceClient <-- JdbcConnector : "依赖" +BaseJdbcDataSourceInfo <-- JdbcConnector : "使用" +``` + +**图示来源** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) + +**本节来源** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +### BaseJdbcExecutor抽象类 + +`BaseJdbcExecutor`提供了JDBC执行器的通用实现,封装了SQL查询的通用逻辑: + +```mermaid +classDiagram +class BaseJdbcExecutor { +-DataSourceClient dataSourceClient ++BaseJdbcExecutor(DataSourceClient) ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++deleteData(ExecuteRequestParam) ConnectorResponse ++query(JdbcTemplate,String,int) ListWithQueryColumn +} +class ExecuteRequestParam { ++String dataSourceParam ++String script ++int limit ++int pageNumber ++int pageSize +} +class ListWithQueryColumn { ++Map[]String,Object~~ result ++QueryColumn[] columns +} +class JdbcTemplate { ++query(String,RowMapper) T[] ++queryForList(String) Map[]String,Object~~ ++setFetchSize(int) void +} +BaseJdbcExecutor <|-- MysqlExecutor : "继承" +BaseJdbcExecutor <|-- PostgreSqlExecutor : "继承" +BaseJdbcExecutor <|-- OracleExecutor : "继承" +ExecuteRequestParam <-- BaseJdbcExecutor : "作为参数" +ListWithQueryColumn <-- BaseJdbcExecutor : "返回类型" +JdbcTemplate <-- BaseJdbcExecutor : "使用" +DataSourceClient <-- BaseJdbcExecutor : "依赖" +``` + +**图示来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +**本节来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +### JdbcDataSourceClient实现 + +`JdbcDataSourceClient`实现了`DataSourceClient`接口,负责数据源的创建和连接管理: + +```mermaid +classDiagram +class JdbcDataSourceClient { ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map~String,Object~) DataSource ++getDataSource(Properties) DataSource ++getConnection(BaseJdbcDataSourceInfo) Connection ++getConnection(Map~String,Object~) Connection ++getConnection(Map~String,Object~,Logger) Connection ++getConnection(Properties) Connection ++getJdbcTemplate(BaseJdbcDataSourceInfo) JdbcTemplate +} +class JdbcDataSourceManager { ++getInstance() JdbcDataSourceManager ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map~String,Object~) DataSource ++getDataSource(Properties) DataSource +} +class DataSource { ++getConnection() Connection +} +class Connection { ++close() void +} +class JdbcTemplate { ++JdbcTemplate(DataSource) ++setFetchSize(int) void +} +JdbcDataSourceClient --> JdbcDataSourceManager : "委托" +JdbcDataSourceClient --> DataSource : "创建" +JdbcDataSourceClient --> Connection : "获取" +JdbcDataSourceClient --> JdbcTemplate : "创建" +``` + +**图示来源** +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) + +**本节来源** +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) + +## 具体数据源插件实现 + +具体数据源插件通过继承JDBC通用实现层的基类,针对特定数据库进行定制化实现。 + +### MySQL插件实现 + +MySQL插件通过`MysqlConnectorFactory`工厂类创建,实现了MySQL特有的连接参数和SQL方言: + +```mermaid +classDiagram +class MysqlConnectorFactory { ++getConnectorParameterConverter() ParameterConverter ++getDialect() Dialect ++getConnector() Connector ++getExecutor() Executor ++getConfigBuilder() ConfigBuilder ++getMetricScript() MetricScript +} +class MysqlDialect { ++getDriver() String ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++quoteIdentifier(String) String ++getQuoteIdentifier() String +} +class MysqlParameterConverter { ++convert(Map~String,String~) Map~String,String~ +} +class MysqlConfigBuilder { ++build(Map~String,String~) Map~String,String~ +} +class MysqlMetricScript { ++getScript(Map~String,String~) String +} +MysqlConnectorFactory --> MysqlDialect : "创建" +MysqlConnectorFactory --> MysqlParameterConverter : "创建" +MysqlConnectorFactory --> MysqlConfigBuilder : "创建" +MysqlConnectorFactory --> MysqlMetricScript : "创建" +MysqlConnectorFactory --> MysqlConnector : "创建" +MysqlConnectorFactory --> MysqlExecutor : "创建" +MysqlDialect <|-- JdbcDialect : "继承" +MysqlParameterConverter <|-- ParameterConverter : "实现" +MysqlConfigBuilder <|-- ConfigBuilder : "实现" +MysqlMetricScript <|-- MetricScript : "实现" +``` + +**图示来源** +- [MysqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnectorFactory.java) +- [MysqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDialect.java) + +**本节来源** +- [MysqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnectorFactory.java) +- [MysqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDialect.java) + +### PostgreSQL插件实现 + +PostgreSQL插件的实现与MySQL类似,但针对PostgreSQL的特性进行了定制: + +```mermaid +classDiagram +class PostgreSqlConnectorFactory { ++getConnectorParameterConverter() ParameterConverter ++getDialect() Dialect ++getConnector() Connector ++getExecutor() Executor ++getConfigBuilder() ConfigBuilder ++getTypeConverter() TypeConverter ++getMetricScript() MetricScript +} +class PostgreSqlDialect { ++getDriver() String +} +class PostgreSqlParameterConverter { ++convert(Map~String,String~) Map~String,String~ +} +class PostgreSqlConfigBuilder { ++build(Map~String,String~) Map~String,String~ +} +class PostgreSqlTypeConverter { ++convertToOriginType(DataType) String ++convertToDataType(String) DataType +} +class PostgreSqlMetricScript { ++getScript(Map~String,String~) String +} +PostgreSqlConnectorFactory --> PostgreSqlDialect : "创建" +PostgreSqlConnectorFactory --> PostgreSqlParameterConverter : "创建" +PostgreSqlConnectorFactory --> PostgreSqlConfigBuilder : "创建" +PostgreSqlConnectorFactory --> PostgreSqlTypeConverter : "创建" +PostgreSqlConnectorFactory --> PostgreSqlMetricScript : "创建" +PostgreSqlConnectorFactory --> PostgreSqlConnector : "创建" +PostgreSqlConnectorFactory --> PostgreSqlExecutor : "创建" +PostgreSqlDialect <|-- JdbcDialect : "继承" +PostgreSqlParameterConverter <|-- ParameterConverter : "实现" +PostgreSqlConfigBuilder <|-- ConfigBuilder : "实现" +PostgreSqlTypeConverter <|-- TypeConverter : "实现" +PostgreSqlMetricScript <|-- MetricScript : "实现" +``` + +**图示来源** +- [PostgreSqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnectorFactory.java) +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) + +**本节来源** +- [PostgreSqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnectorFactory.java) +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) + +## SPI插件发现机制 + +DataVines Connector组件通过Java的SPI(Service Provider Interface)机制实现插件的动态发现和加载。 + +```mermaid +sequenceDiagram +participant Application as 应用程序 +participant ServiceLoader as ServiceLoader +participant SPIFile as META-INF/services文件 +participant PluginFactory as 插件工厂 +Application->>ServiceLoader : ServiceLoader.load(ConnectorFactory.class) +ServiceLoader->>SPIFile : 查找META-INF/services/io.datavines.connector.api.ConnectorFactory +SPIFile-->>ServiceLoader : 返回实现类列表 +loop 每个实现类 +ServiceLoader->>PluginFactory : 实例化工厂类 +PluginFactory-->>ServiceLoader : 返回实例 +end +ServiceLoader-->>Application : 返回工厂实例集合 +Application->>PluginFactory : 调用getConnector()获取连接器 +PluginFactory-->>Application : 返回具体连接器实例 +``` + +**图示来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +**本节来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +## 连接池与连接管理 + +Connector组件通过`JdbcDataSourceManager`实现连接池管理,确保连接的高效复用和资源释放。 + +```mermaid +flowchart TD +Start([获取连接]) --> CheckPool["检查连接池"] +CheckPool --> PoolHit{"连接池命中?"} +PoolHit --> |是| ReturnConn["返回池中连接"] +PoolHit --> |否| CreateConn["创建新连接"] +CreateConn --> ConfigConn["配置连接参数"] +ConfigConn --> AddPool["添加到连接池"] +AddPool --> ReturnConn +ReturnConn --> End([返回连接]) +UseConn([使用连接]) --> ExecuteSQL["执行SQL操作"] +ExecuteSQL --> CheckError{"发生错误?"} +CheckError --> |是| HandleError["处理错误"] +CheckError --> |否| Complete["操作完成"] +Complete --> ReturnConn2["归还连接"] +HandleError --> ReturnConn2 +ReturnConn2 --> CloseConn["关闭连接"] +CloseConn --> End2([结束]) +``` + +**图示来源** +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) + +**本节来源** +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) + +## SQL执行与结果处理 + +SQL执行和结果处理流程确保了查询的安全性和结果的正确性。 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Executor as 执行器 +participant JdbcTemplate as JdbcTemplate +participant Connection as 数据库连接 +participant Database as 数据库 +Client->>Executor : queryForPage(param) +Executor->>Executor : 验证参数 +Executor->>Executor : 获取JdbcTemplate +Executor->>JdbcTemplate : queryForPage(sql, limit, page, size) +JdbcTemplate->>Connection : 获取连接 +Connection->>Database : 执行SQL查询 +Database-->>Connection : 返回结果集 +Connection-->>JdbcTemplate : 返回结果 +JdbcTemplate-->>Executor : 返回ListWithQueryColumn +Executor-->>Client : 返回ConnectorResponse +``` + +**图示来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +**本节来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +## 跨数据库方言兼容性 + +通过`Dialect`接口的分层实现,Connector组件实现了对不同数据库方言的兼容性处理。 + +```mermaid +classDiagram +class Dialect { +<> ++getDriver() String ++quoteIdentifier(String) String ++getTableExistsQuery(String) String ++getCountQuery(String) String +} +class JdbcDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++getPageFromResultSet(Statement,ResultSet,String,int,int) ResultList +} +class MysqlDialect { ++getDriver() String ++quoteIdentifier(String) String ++getQuoteIdentifier() String ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean +} +class PostgreSqlDialect { ++getDriver() String +} +class OracleDialect { ++getDriver() String ++quoteIdentifier(String) String ++getQuoteIdentifier() String +} +class HiveDialect { ++getDriver() String ++getExcludeDatabases() String[] +} +Dialect <|-- JdbcDialect +JdbcDialect <|-- MysqlDialect +JdbcDialect <|-- PostgreSqlDialect +JdbcDialect <|-- OracleDialect +JdbcDialect <|-- HiveDialect +``` + +**图示来源** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) + +**本节来源** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) + +## 安全与防护机制 + +Connector组件实现了多种安全机制,包括SQL注入防护和连接参数加密。 + +```mermaid +flowchart TD +Start([开始]) --> ParamValidation["参数验证"] +ParamValidation --> SQLInjectionCheck["SQL注入检查"] +SQLInjectionCheck --> |存在风险| Reject["拒绝请求"] +SQLInjectionCheck --> |安全| ConnectionCheck["连接验证"] +ConnectionCheck --> |失败| HandleError["处理错误"] +ConnectionCheck --> |成功| ExecuteSQL["执行SQL"] +ExecuteSQL --> ResultProcessing["结果处理"] +ResultProcessing --> Log["记录日志"] +Log --> End([结束]) +Reject --> End +HandleError --> End +``` + +**图示来源** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +**本节来源** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +## 扩展新数据源连接器 + +扩展新的数据源连接器需要遵循特定的实现模式,通过继承和实现相关接口来完成。 + +```mermaid +flowchart TD +Start([创建新连接器]) --> CreateFactory["创建工厂类"] +CreateFactory --> ImplementInterface["实现ConnectorFactory接口"] +ImplementInterface --> OverrideMethods["重写必要方法"] +OverrideMethods --> CreateConnector["创建连接器类"] +CreateConnector --> ExtendJdbcConnector["继承JdbcConnector"] +ExtendJdbcConnector --> ImplementDialect["实现Dialect"] +ImplementDialect --> CreateDialect["创建方言类"] +CreateDialect --> OverrideDriver["重写getDriver方法"] +OverrideDriver --> ImplementSpecific["实现特定逻辑"] +ImplementSpecific --> RegisterSPI["注册SPI"] +RegisterSPI --> CreateSPIFile["创建META-INF/services文件"] +CreateSPIFile --> AddClassName["添加类名"] +AddClassName --> Test["测试验证"] +Test --> End([完成]) +``` + +**图示来源** +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java) + +**本节来源** +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java) + +## 总结 + +DataVines Connector组件通过精心设计的插件化架构,实现了对多种数据源的统一管理和灵活扩展。其核心设计特点包括: + +1. **清晰的接口分层**:通过`Connector`、`Dialect`、`Executor`等接口的分离,实现了关注点的解耦。 +2. **通用JDBC实现**:提供了`JdbcConnector`和`BaseJdbcExecutor`等基类,为支持JDBC的数据源提供了通用实现。 +3. **SPI插件机制**:利用Java SPI机制实现了插件的动态发现和加载,支持20多种数据源的扩展。 +4. **方言兼容性**:通过`Dialect`接口的分层实现,处理了不同数据库的SQL语法差异。 +5. **连接池管理**:通过`JdbcDataSourceManager`实现了连接的高效复用和资源管理。 +6. **安全防护**:实现了SQL注入防护和连接参数加密等安全机制。 + +这种设计使得DataVines能够灵活地支持各种数据源,同时保持了代码的可维护性和扩展性,为大数据质量监控提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/Engine\347\273\204\344\273\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/Engine\347\273\204\344\273\266.md" new file mode 100644 index 00000000..0b726553 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/Engine\347\273\204\344\273\266.md" @@ -0,0 +1,309 @@ +# Engine组件 + + +**本文档中引用的文件** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java) +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java) +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java) +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java) +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) + + +## 目录 +1. [引言](#引言) +2. [执行引擎抽象机制](#执行引擎抽象机制) +3. [核心执行流程](#核心执行流程) +4. [Spark执行器实现](#spark执行器实现) +5. [Flink执行器实现](#flink执行器实现) +6. [任务生命周期管理](#任务生命周期管理) +7. [执行参数配置](#执行参数配置) +8. [资源调度平台适配](#资源调度平台适配) +9. [性能特征与适用场景](#性能特征与适用场景) + +## 引言 + +DataVines Engine组件提供了统一的执行引擎抽象机制,用于支持多种计算引擎(如Spark和Flink)的数据质量检测任务执行。该组件通过接口抽象和模板方法模式,实现了对不同计算引擎的统一管理和调度,同时支持多种资源调度平台(如Yarn、Livy)的适配。本文档将深入解析Engine组件的执行引擎抽象机制与任务执行流程。 + +## 执行引擎抽象机制 + +DataVines Engine组件通过`EngineExecutor`接口定义了执行引擎的统一契约,所有具体的执行器实现都必须遵循这一接口规范。该接口采用SPI(Service Provider Interface)机制进行扩展,允许动态加载不同类型的执行器。 + +```mermaid +classDiagram +class EngineExecutor { +<> ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++isCancel() boolean ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest +} +class AbstractEngineExecutor { +-JobExecutionRequest jobExecutionRequest +-Logger logger +-boolean cancel +-ProcessResult processResult ++logHandle(String[]) void ++isCancel() boolean +#buildCommand() String +} +class AbstractYarnEngineExecutor { +-ShellCommandProcess shellCommandProcess ++cancel() void +} +EngineExecutor <|-- AbstractEngineExecutor +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +``` + +**图源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) + +**本节来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) + +## 核心执行流程 + +DataVines Engine组件的任务执行流程遵循标准的初始化-执行-清理生命周期模式。执行流程从`init`方法开始,经过`execute`方法执行核心逻辑,最后通过`after`方法进行资源清理。 + +```mermaid +flowchart TD +Start([任务开始]) --> Init["初始化执行器"] +Init --> BuildCommand["构建执行命令"] +BuildCommand --> Execute["执行命令"] +Execute --> Monitor["监控执行状态"] +Monitor --> CheckCancel{"是否取消?"} +CheckCancel --> |是| Cancel["取消任务"] +CheckCancel --> |否| CheckComplete{"是否完成?"} +CheckComplete --> |否| Monitor +CheckComplete --> |是| GetResult["获取执行结果"] +GetResult --> End([任务结束]) +Cancel --> KillApp["终止YARN应用"] +KillApp --> End +``` + +**图源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) + +## Spark执行器实现 + +Spark执行器通过`SparkEngineExecutor`类实现,继承自`AbstractYarnEngineExecutor`,专门用于提交Spark任务到YARN集群。该实现通过构建`spark-submit`命令来启动Spark应用程序。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant SparkExecutor as "SparkEngineExecutor" +participant ShellProcess as "ShellCommandProcess" +participant YARN as "YARN集群" +Client->>SparkExecutor : init() +SparkExecutor->>SparkExecutor : 初始化参数 +SparkExecutor->>SparkExecutor : buildCommand() +SparkExecutor->>SparkExecutor : 构建spark-submit命令 +SparkExecutor->>ShellProcess : execute() +ShellProcess->>ShellProcess : 生成shell脚本 +ShellProcess->>YARN : 提交Spark任务 +YARN-->>ShellProcess : 返回执行结果 +ShellProcess-->>SparkExecutor : 返回ProcessResult +SparkExecutor-->>Client : 完成执行 +``` + +**图源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L152) +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java#L25-L130) + +**本节来源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L152) +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java#L25-L130) + +## Flink执行器实现 + +Flink执行器通过`FlinkEngineExecutor`类实现,同样继承自`AbstractYarnEngineExecutor`,用于提交Flink任务到YARN集群。与Spark执行器类似,它通过构建`flink`命令来启动Flink作业。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant FlinkExecutor as "FlinkEngineExecutor" +participant ShellProcess as "ShellCommandProcess" +participant YARN as "YARN集群" +Client->>FlinkExecutor : init() +FlinkExecutor->>FlinkExecutor : 初始化参数 +FlinkExecutor->>FlinkExecutor : buildCommand() +FlinkExecutor->>FlinkExecutor : 构建flink命令 +FlinkExecutor->>ShellProcess : execute() +ShellProcess->>ShellProcess : 生成shell脚本 +ShellProcess->>YARN : 提交Flink任务 +YARN-->>ShellProcess : 返回执行结果 +ShellProcess-->>FlinkExecutor : 返回ProcessResult +FlinkExecutor-->>Client : 完成执行 +Client->>FlinkExecutor : cancel() +FlinkExecutor->>ShellProcess : cancel() +FlinkExecutor->>FlinkExecutor : killYarnApplication() +FlinkExecutor->>YARN : 终止YARN应用 +``` + +**图源** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L38-L182) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L24-L124) + +**本节来源** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L38-L182) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L24-L124) + +## 任务生命周期管理 + +DataVines Engine组件对任务的完整生命周期进行了精细化管理,包括任务的提交、状态监控、结果获取和取消操作。每个任务都有唯一的执行ID,用于在YARN等资源调度平台上进行跟踪。 + +```mermaid +stateDiagram-v2 +[*] --> INITIALIZING +INITIALIZING --> EXECUTING : init() +EXECUTING --> MONITORING : execute() +MONITORING --> COMPLETED : 成功完成 +MONITORING --> FAILED : 执行失败 +MONITORING --> CANCELING : cancel() +CANCELING --> CANCELLED : 任务已取消 +COMPLETED --> [*] +FAILED --> [*] +CANCELLED --> [*] +``` + +**图源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) + +**本节来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) + +## 执行参数配置 + +DataVines Engine组件支持灵活的执行参数配置,允许用户为不同的计算引擎指定特定的执行参数。这些参数通过JSON格式传递,并在执行器初始化时解析。 + +### Spark执行参数 + +Spark执行参数通过`SparkParameters`类定义,包含以下主要配置项: + +| 参数名称 | 描述 | 示例值 | +|--------|------|-------| +| mainJar | 主JAR包路径 | /path/to/data-quality.jar | +| mainClass | 主类名称 | io.datavines.engine.spark.core.SparkDataVinesBootstrap | +| deployMode | 部署模式 | cluster | +| driverCores | Driver核心数 | 1 | +| driverMemory | Driver内存 | 1g | +| numExecutors | Executor数量 | 2 | +| executorCores | 每个Executor核心数 | 2 | +| executorMemory | 每个Executor内存 | 2g | +| appName | 应用名称 | data-quality-job | +| queue | YARN队列 | default | +| others | 其他参数 | --conf spark.yarn.tags=job123 | + +**本节来源** +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java#L19-L219) +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L26-L68) + +### Flink执行参数 + +Flink执行参数通过`FlinkParameters`类定义,包含以下主要配置项: + +| 参数名称 | 描述 | 示例值 | +|--------|------|-------| +| mainJar | 主JAR包路径 | /path/to/data-quality-flink.jar | +| mainClass | 主类名称 | io.datavines.engine.flink.core.FlinkDataVinesBootstrap | +| deployMode | 部署模式 | yarn-per-job | +| taskManagerCount | TaskManager数量 | 2 | +| taskManagerMemory | TaskManager内存 | 2g | +| jobManagerMemory | JobManager内存 | 1g | +| parallelism | 并行度 | 4 | +| yarnQueue | YARN队列 | default | +| jobName | 作业名称 | flink-data-quality | +| flinkOthers | 其他Flink参数 | -Dexecution.checkpointing.interval=60000 | + +**本节来源** +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) + +## 资源调度平台适配 + +DataVines Engine组件支持多种资源调度平台,通过`ResourceSchedulePlatformType`枚举定义了不同的调度平台类型。目前支持本地、YARN和K8S三种调度方式。 + +```mermaid +classDiagram +class ResourceSchedulePlatformType { +<> ++LOCAL(0,"local") ++YARN(1,"yarn") ++K8S(2,"k8s") ++of(int) ResourceSchedulePlatformType ++of(String) ResourceSchedulePlatformType ++getCode() int ++getDescription() String +} +class AbstractYarnEngineExecutor { ++cancel() void +-killYarnApplication() void +} +class AbstractLivyEngineExecutor { ++cancel() void +} +ResourceSchedulePlatformType --> AbstractYarnEngineExecutor : "用于" +ResourceSchedulePlatformType --> AbstractLivyEngineExecutor : "用于" +``` + +**图源** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java#L19-L60) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java#L23-L36) + +**本节来源** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java#L19-L60) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) + +## 性能特征与适用场景 + +DataVines Engine组件针对不同的计算引擎和资源调度平台,展现出不同的性能特征和适用场景。 + +### Spark执行模式 + +Spark执行模式适用于批处理场景,特别是大规模数据质量检测任务。其性能特征包括: + +- **启动时间**:相对较长,因为需要启动Driver和Executor进程 +- **资源利用率**:高,能够充分利用集群资源进行并行处理 +- **容错性**:强,支持RDD的容错机制 +- **适用场景**:大规模数据集的批处理质量检测 + +### Flink执行模式 + +Flink执行模式适用于流处理和微批处理场景,其性能特征包括: + +- **启动时间**:相对较短,特别是使用yarn-session模式时 +- **延迟**:低,适合实时或近实时数据质量检测 +- **资源利用率**:中等,需要持续运行JobManager和TaskManager +- **适用场景**:实时数据流的质量监控和检测 + +### 资源调度平台比较 + +| 调度平台 | 启动速度 | 资源隔离 | 管理复杂度 | 适用场景 | +|--------|--------|--------|--------|--------| +| 本地模式 | 快 | 低 | 低 | 开发测试 | +| YARN | 中等 | 高 | 中等 | 生产环境批处理 | +| K8S | 中等 | 高 | 高 | 云原生环境 | + +**本节来源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L152) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L38-L182) +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java#L19-L60) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/Server\347\273\204\344\273\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/Server\347\273\204\344\273\266.md" new file mode 100644 index 00000000..8e23b56a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/Server\347\273\204\344\273\266.md" @@ -0,0 +1,207 @@ +# Server组件 + + +**本文档中引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [JobScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobScheduleService.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +DataVines Server组件是整个数据质量平台的核心服务模块,承担着API网关、任务调度中心和状态管理器的多重职责。该组件基于Spring Boot框架构建,采用MVC架构模式,实现了RESTful API接口、JWT身份验证机制以及全局异常处理等关键功能。通过集成Quartz调度器,实现了定时任务的创建、触发和管理。本文档将深入分析其架构设计与核心职责,详细阐述各项功能的实现机制。 + +## 项目结构 +DataVines Server组件的项目结构清晰地体现了其模块化设计。核心代码位于`datavines-server`模块中,主要包含API接口、配置、数据质量检查、注册中心、存储库、调度器和工具类等子模块。其中,`api`包负责提供RESTful API接口,`dqc`包实现数据质量检查相关功能,`scheduler`包负责任务调度,`repository`包处理数据持久化操作。 + +```mermaid +graph TD +A[datavines-server] --> B[api] +A --> C[config] +A --> D[dqc] +A --> E[enums] +A --> F[registry] +A --> G[repository] +A --> H[scheduler] +A --> I[utils] +A --> J[DataVinesServer.java] +B --> K[controller] +B --> L[dto] +B --> M[inteceptor] +D --> N[command] +D --> O[coordinator] +D --> P[executor] +G --> Q[entity] +G --> R[mapper] +G --> S[service] +``` + +**图示来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) + +## 核心组件 +DataVines Server的核心组件包括API网关、任务调度引擎和状态管理器。API网关通过Spring MVC实现RESTful接口,处理所有客户端请求;任务调度引擎基于Quartz框架,负责定时任务的管理和执行;状态管理器维护系统运行时的状态信息,确保各组件间的协调工作。 + +**组件来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L50-L159) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) + +## 架构概述 +DataVines Server采用典型的分层架构设计,从上到下分为接口层、业务逻辑层和数据访问层。接口层通过Spring MVC处理HTTP请求,业务逻辑层实现核心功能,数据访问层使用MyBatis Plus进行数据库操作。系统通过JWT实现身份验证,利用Quartz实现任务调度,并通过注册中心实现服务发现和状态同步。 + +```mermaid +graph TD +A[客户端] --> B[API网关] +B --> C[身份验证] +C --> D[业务逻辑] +D --> E[任务调度] +D --> F[数据访问] +E --> G[Quartz调度器] +F --> H[数据库] +I[注册中心] --> D +J[配置中心] --> D +``` + +**图示来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L75-L108) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L39-L59) + +## 详细组件分析 + +### API网关与MVC架构 +DataVines Server的API网关基于Spring Boot的MVC架构实现,通过@Controller和@RequestMapping注解定义RESTful接口。系统使用Swagger生成API文档,便于开发者理解和使用。接口层与业务逻辑层通过DTO对象进行数据传输,确保了接口的稳定性和灵活性。 + +#### RESTful API设计 +系统遵循RESTful设计原则,使用标准的HTTP方法(GET、POST、PUT、DELETE)对应资源的查询、创建、更新和删除操作。API路径采用层次化设计,如`/api/job/schedule`表示作业调度相关的接口。 + +**组件来源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L39-L77) +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java#L36-L71) + +### JWT身份验证机制 +系统采用JWT(JSON Web Token)实现无状态的身份验证机制。TokenManager组件负责JWT令牌的生成、验证和刷新。用户登录成功后,服务器生成包含用户信息的JWT令牌并返回给客户端,后续请求通过在HTTP头中携带该令牌进行身份验证。 + +```mermaid +sequenceDiagram +participant 客户端 +participant LoginController +participant TokenManager +participant UserService +客户端->>LoginController : POST /login +LoginController->>UserService : 验证用户凭据 +UserService-->>LoginController : 用户信息 +LoginController->>TokenManager : 生成JWT令牌 +TokenManager-->>LoginController : JWT令牌 +LoginController-->>客户端 : 返回令牌和用户信息 +``` + +**图示来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L40-L197) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L54-L58) + +### 全局异常处理 +系统通过@ControllerAdvice注解实现全局异常处理,DataVinesExceptionHandler类统一处理各种异常情况,包括业务异常、参数验证异常和系统异常。异常处理机制能够捕获异常并返回标准化的错误响应,便于客户端进行错误处理。 + +**组件来源** +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java#L42-L133) + +### 任务调度中心 +任务调度中心是DataVines Server的核心功能之一,负责管理和执行各种定时任务。系统基于Quartz调度器实现,通过JobScheduleController提供API接口,允许用户创建、更新和删除定时任务。 + +#### Quartz调度器集成 +系统在application.yaml中配置Quartz使用JDBC JobStore,实现集群环境下的任务调度。通过配置`org.quartz.jobStore.isClustered: true`,确保多个Server实例能够协同工作,避免任务重复执行。 + +```mermaid +classDiagram +class JobScheduler { ++JobExecuteManager jobExecuteManager ++Register register ++run() void ++executionOutOfThreshold(String) boolean +} +class JobScheduleController { ++JobScheduleService jobScheduleService ++createOrUpdateJob(JobScheduleCreateOrUpdate) Object ++getListByJobId(Long) Object ++showCron(MapParam) Object +} +class JobScheduleService { ++createOrUpdate(JobScheduleCreateOrUpdate) JobSchedule ++getByJobId(Long) JobSchedule ++getCron(MapParam) String[] +} +JobScheduleController --> JobScheduleService : "依赖" +JobScheduler --> JobExecuteManager : "使用" +JobScheduler --> Register : "依赖" +``` + +**图示来源** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L39-L155) +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java#L41-L71) +- [JobScheduleService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobScheduleService.java#L28-L43) + +### 状态管理器 +状态管理器负责维护系统的运行时状态,包括任务执行状态、服务注册状态等。通过RegistryHolder和Register组件,实现服务的注册与发现,确保系统各组件能够及时感知状态变化。 + +**组件来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L61-L63) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) + +## 依赖分析 +DataVines Server组件依赖于多个外部库和内部模块。主要依赖包括Spring Boot生态系统、MyBatis Plus、Quartz调度器、HikariCP连接池等。通过Maven进行依赖管理,确保各组件版本的兼容性。 + +```mermaid +graph TD +A[DataVines Server] --> B[Spring Boot] +A --> C[MyBatis Plus] +A --> D[Quartz] +A --> E[HikariCP] +A --> F[JWT] +A --> G[datavines-common] +A --> H[datavines-core] +A --> I[datavines-registry] +``` + +**图示来源** +- [pom.xml](file://datavines-server/pom.xml) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L19-L36) + +## 性能考虑 +在高并发场景下,DataVines Server通过多种机制优化性能。首先,使用HikariCP作为数据库连接池,提供高效的连接管理;其次,通过Quartz的集群模式实现任务调度的负载均衡;最后,利用缓存机制减少数据库访问频率。 + +系统还实现了资源检查机制,在执行任务前检查CPU负载和内存使用情况,避免因资源不足导致系统不稳定。通过配置`max.cpu.load.avg`和`reserved.memory`参数,可以灵活调整资源使用策略。 + +## 故障排除指南 +当系统出现故障时,可以按照以下步骤进行排查: +1. 检查日志文件,定位错误信息 +2. 验证数据库连接是否正常 +3. 检查Quartz调度器状态 +4. 确认服务注册中心是否正常工作 +5. 验证JWT令牌的有效性 + +对于任务调度失败的情况,需要检查任务配置是否正确,执行环境是否满足要求,以及是否有足够的系统资源。 + +**故障排除来源** +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java#L48-L95) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L122-L131) + +## 结论 +DataVines Server组件通过合理的架构设计和功能实现,成功地承担了API网关、任务调度中心和状态管理器的多重职责。基于Spring Boot的MVC架构提供了稳定可靠的RESTful API接口,JWT身份验证机制确保了系统的安全性,Quartz调度器的集成实现了灵活的任务调度功能。系统在高并发场景下的性能优化策略,保证了其在生产环境中的稳定运行。未来可以进一步优化任务调度算法,提升系统的整体性能和可靠性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206.md" new file mode 100644 index 00000000..e075ef49 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\240\270\345\277\203\346\236\266\346\236\204/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206/\347\273\204\344\273\266\350\201\214\350\264\243\345\210\222\345\210\206.md" @@ -0,0 +1,230 @@ +# 组件职责划分 + + +**本文档引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [MySqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MySqlConnector.java) +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) + + +## 目录 +1. [引言](#引言) +2. [Server组件职责](#server组件职责) +3. [Engine组件职责](#engine组件职责) +4. [Connector组件职责](#connector组件职责) +5. [组件间调用时序](#组件间调用时序) +6. [分层架构优势](#分层架构优势) +7. [结论](#结论) + +## 引言 +DataVines是一个数据质量监控平台,采用分层架构设计,将系统划分为三大核心组件:Server组件、Engine组件和Connector组件。这种架构设计实现了关注点分离,提高了系统的可维护性和可扩展性。本文档详细阐述这三个核心组件的职责划分,分析其关键技术实现,并通过时序图展示组件间的调用关系。 + +## Server组件职责 +Server组件是DataVines的核心,负责API网关、任务调度和状态管理。它基于Spring Boot框架构建MVC架构,实现了RESTful API接口,为前端UI和其他客户端提供服务。Server组件的核心职责包括任务调度、状态管理和API网关功能。 + +在任务调度方面,Server组件集成了Quartz调度器(通过CommonTaskScheduler实现),负责定时触发数据质量检查任务。`CommonTaskScheduler`类继承自Thread,通过轮询机制从任务队列中获取待执行的任务命令,并将其提交给任务管理器进行处理。调度器还实现了资源检查机制,确保在系统资源充足的情况下才执行任务,避免因资源不足导致系统不稳定。 + +状态管理是Server组件的另一项重要职责。`JobExecuteManager`类负责管理所有正在执行的任务的状态,维护一个未完成任务的映射表(unFinishedJobExecutionMap),并提供任务的启动、停止和状态查询功能。该组件还实现了任务超时机制,使用HashedWheelTimer定时器监控任务执行时间,一旦任务超时就自动终止。 + +```mermaid +classDiagram +class DataVinesServer { ++main(String[] args) void +-initializeAndStart() void +-close(String cause) void +} +class CommonTaskScheduler { +-jobExternalService JobExternalService +-commonTaskManager CommonTaskManager +-register Register ++run() void +} +class JobExecuteManager { +-jobExecutionQueue LinkedBlockingQueue~CommandContext~ +-unFinishedJobExecutionMap ConcurrentHashMap~Long, JobExecutionRequest~ +-responseQueue LinkedBlockingQueue~JobExecutionResponseContext~ +-executorService ExecutorService +-jobExecuteService ExecutorService ++start() void ++addKillCommand(Long jobExecutionId) void ++addExecuteCommand(JobExecution jobExecution) void ++close() void +} +DataVinesServer --> CommonTaskScheduler : "初始化并启动" +DataVinesServer --> JobExecuteManager : "初始化并启动" +CommonTaskScheduler --> JobExecuteManager : "提交任务" +``` + +**图示来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L48-L159) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L31-L90) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L616) + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L48-L159) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L31-L90) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L616) + +## Engine组件职责 +Engine组件负责执行引擎的抽象和任务执行,是DataVines的计算核心。该组件通过接口抽象的方式,实现了对Spark、Flink等多种计算引擎的适配,使得系统能够灵活地选择最适合的计算框架来执行数据质量检查任务。 + +`EngineExecutor`接口是Engine组件的核心抽象,定义了执行器的生命周期方法,包括init()、execute()、after()、cancel()等。所有具体的执行器实现都必须实现这个接口,从而保证了统一的调用方式。这种设计模式使得系统可以轻松地扩展支持新的计算引擎,只需实现相应的执行器类即可。 + +对于Spark引擎,`SparkEngineExecutor`类继承自`AbstractYarnEngineExecutor`,负责构建和提交Spark作业。该类通过`buildCommand()`方法生成spark-submit命令,将任务配置、JAR包路径、主类等参数组装成完整的命令行。特别地,该实现还支持动态加载插件JAR包,通过扫描插件目录并将所有JAR包添加到--jars参数中,实现了插件化扩展能力。 + +```mermaid +classDiagram +class EngineExecutor { +<> ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++isCancel() boolean ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest +} +class SparkEngineExecutor { +-configurations Configurations ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++buildCommand() String +} +class FlinkEngineExecutor { +-configurations Configurations ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++buildCommand() String +} +EngineExecutor <|-- SparkEngineExecutor +EngineExecutor <|-- FlinkEngineExecutor +SparkEngineExecutor --> SparkParameters : "使用" +FlinkEngineExecutor --> FlinkParameters : "使用" +``` + +**图示来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L152) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) + +**本节来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L152) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) + +## Connector组件职责 +Connector组件负责数据源连接和SQL执行,是DataVines与各种数据存储系统交互的桥梁。该组件采用插件化设计,支持MySQL、PostgreSQL、Oracle、SQL Server等20多种数据源,通过统一的接口抽象,实现了对不同数据库系统的适配。 + +`Connector`接口是Connector组件的核心,定义了获取数据库、表、列等元数据的方法,以及测试连接、执行SQL等基本操作。所有具体的连接器实现都继承自`JdbcConnector`抽象类,该类提供了JDBC连接的通用实现,包括连接管理、元数据查询、结果集处理等基础功能。 + +为了支持多种数据库,DataVines采用了工厂模式和SPI(Service Provider Interface)机制。每个数据库类型都有对应的`DataSourceInfo`实现类,用于解析连接参数并生成JDBC URL。例如,`MySqlConnector`和`PostgreSqlConnector`分别实现了MySQL和PostgreSQL的特定连接逻辑,包括获取数据库列表、表列表和列信息的方法。 + +```mermaid +classDiagram +class Connector { +<> ++getDatabases(GetDatabasesRequestParam) ConnectorResponse ++getTables(GetTablesRequestParam) ConnectorResponse ++getColumns(GetColumnsRequestParam) ConnectorResponse ++testConnect(TestConnectionRequestParam) ConnectorResponse ++keyProperties() String[] +} +class JdbcConnector { +-dataSourceClient DataSourceClient ++getDatabases(GetDatabasesRequestParam) ConnectorResponse ++getTables(GetTablesRequestParam) ConnectorResponse ++getColumns(GetColumnsRequestParam) ConnectorResponse ++testConnect(TestConnectionRequestParam) ConnectorResponse +} +class MySqlConnector { ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo ++getMetadataDatabases(Connection) ResultSet +} +class PostgreSqlConnector { ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo ++getMetadataDatabases(Connection) ResultSet ++getMetadataTables(DatabaseMetaData, String, String) ResultSet +} +Connector <|-- JdbcConnector +JdbcConnector <|-- MySqlConnector +JdbcConnector <|-- PostgreSqlConnector +JdbcConnector --> DataSourceClient : "依赖" +MySqlConnector --> MysqlDataSourceInfo : "使用" +PostgreSqlConnector --> PostgreSqlDataSourceInfo : "使用" +``` + +**图示来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L24-L72) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L42-L283) +- [MySqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MySqlConnector.java#L28-L45) +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java#L28-L54) + +**本节来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L24-L72) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L42-L283) +- [MySqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MySqlConnector.java#L28-L45) +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java#L28-L54) + +## 组件间调用时序 +DataVines的三大核心组件通过明确定义的接口进行交互,形成了清晰的调用流程。当用户提交一个数据质量检查任务时,首先由Server组件接收请求,然后调度Engine组件执行任务,Engine组件在执行过程中通过Connector组件访问数据源。 + +```mermaid +sequenceDiagram +participant UI as "用户界面" +participant Server as "Server组件" +participant Engine as "Engine组件" +participant Connector as "Connector组件" +participant Database as "数据库" +UI->>Server : 提交任务请求 +Server->>Server : 验证任务参数 +Server->>Server : 创建JobExecutionRequest +Server->>Engine : 初始化执行器 +Engine->>Engine : 准备执行环境 +Engine->>Connector : 获取数据源连接 +Connector->>Database : 建立JDBC连接 +Database-->>Connector : 返回连接对象 +Connector-->>Engine : 返回DataSourceClient +Engine->>Engine : 构建执行命令 +Engine->>Engine : 执行数据质量检查 +Engine->>Connector : 查询元数据 +Connector->>Database : 执行SQL查询 +Database-->>Connector : 返回查询结果 +Connector-->>Engine : 返回处理结果 +Engine->>Server : 返回执行结果 +Server->>Server : 更新任务状态 +Server-->>UI : 返回任务执行结果 +Note over Server,Engine : 任务执行过程中,Server组件
持续监控任务状态,支持
任务取消和超时处理 +``` + +**图示来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L48-L159) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L616) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L24-L72) + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L48-L159) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L616) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L24-L72) + +## 分层架构优势 +DataVines采用的分层架构设计带来了显著的优势,主要体现在关注点分离和可维护性提升两个方面。 + +首先,通过将系统划分为Server、Engine和Connector三个明确的层次,实现了关注点的完全分离。Server组件专注于任务调度和状态管理,不关心具体的计算逻辑;Engine组件专注于计算引擎的抽象和任务执行,不关心数据源的具体实现;Connector组件专注于数据源的连接和SQL执行,不关心任务的调度策略。这种分离使得每个组件都可以独立开发、测试和优化,大大降低了系统的复杂性。 + +其次,这种架构显著提升了系统的可维护性和可扩展性。由于各组件之间通过明确定义的接口进行交互,当需要修改某个组件的实现时,只要保持接口不变,就不会影响到其他组件。例如,可以轻松地添加对新的计算引擎(如Trino)的支持,只需实现相应的EngineExecutor即可;同样,可以方便地支持新的数据源类型,只需实现相应的Connector即可。 + +此外,插件化设计进一步增强了系统的灵活性。通过SPI机制,新的功能模块可以以插件的形式动态加载,无需修改核心代码。这种设计不仅便于功能扩展,也使得系统更容易适应不同的部署环境和业务需求。 + +## 结论 +DataVines通过Server、Engine和Connector三大核心组件的职责划分,构建了一个高度模块化和可扩展的数据质量监控平台。Server组件作为系统的控制中心,负责任务调度和状态管理;Engine组件作为计算核心,实现了对多种计算引擎的抽象和适配;Connector组件作为数据访问层,支持20多种数据源的插件化设计。这种分层架构不仅实现了关注点的分离,还极大地提升了系统的可维护性和可扩展性,为数据质量监控提供了坚实的技术基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/MySQL\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/MySQL\345\256\236\347\216\260.md" new file mode 100644 index 00000000..9b029142 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/MySQL\345\256\236\347\216\260.md" @@ -0,0 +1,252 @@ +# MySQL实现 + + +**本文档引用的文件** +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java) +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java) +- [RegistryLock.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\RegistryLock.java) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql) +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ServerInfo.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ServerInfo.java) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) + + +## 目录 +1. [引言](#引言) +2. [MySQL注册中心架构](#mysql注册中心架构) +3. [MysqlRegistry服务注册机制](#mysqlregistry服务注册机制) +4. [MysqlServerStateManager服务状态管理](#mysqlserverstatemanager服务状态管理) +5. [分布式锁实现原理](#分布式锁实现原理) +6. [心跳检测与故障剔除](#心跳检测与故障剔除) +7. [数据库表结构设计](#数据库表结构设计) +8. [性能评估与高可用部署](#性能评估与高可用部署) +9. [配置与使用](#配置与使用) +10. [总结](#总结) + +## 引言 + +DataVines MySQL注册中心是基于MySQL数据库实现的服务注册与发现组件,为分布式系统提供可靠的服务状态管理。该注册中心通过数据库表存储服务实例信息,利用数据库的ACID特性确保数据一致性,同时通过心跳机制和分布式锁实现服务的高可用性。本文档详细描述了MySQL注册中心的实现原理,包括服务注册、状态管理、分布式锁、心跳检测等核心机制,为系统架构师和开发人员提供深入的技术参考。 + +## MySQL注册中心架构 + +DataVines MySQL注册中心采用分层架构设计,主要包括服务注册层、状态管理层和存储层。服务注册层通过MysqlRegistry接口提供统一的注册服务,状态管理层由MysqlServerStateManager负责服务实例的生命周期管理,存储层则基于MySQL数据库实现数据持久化。整个架构通过数据库事务保证操作的原子性,通过定时任务实现心跳检测和故障剔除,形成一个完整的服务治理解决方案。 + +```mermaid +graph TB +subgraph "客户端" +Client[服务实例] +end +subgraph "注册中心" +Registry[MysqlRegistry] +StateManager[MysqlServerStateManager] +Mutex[MysqlMutex] +end +subgraph "存储层" +DB[(MySQL数据库)] +end +Client --> Registry +Registry --> StateManager +Registry --> Mutex +StateManager --> DB +Mutex --> DB +``` + +**图源** +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java#L29-L106) +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java#L33-L257) +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java#L36-L218) + +## MysqlRegistry服务注册机制 + +MysqlRegistry是MySQL注册中心的核心实现类,实现了Registry接口,负责服务的注册、发现和分布式锁管理。该类在初始化时创建数据库连接,并实例化MysqlMutex和MysqlServerStateManager组件。服务注册通过调用MysqlServerStateManager的registry方法实现,将服务实例信息写入dv_server表。服务发现通过getActiveServerList方法获取当前活跃的服务列表,支持服务订阅和通知机制,当服务状态发生变化时,通过SubscribeListener通知监听者。 + +```mermaid +classDiagram +class MysqlRegistry { +-MysqlMutex mysqlMutex +-MysqlServerStateManager mysqlServerStateManager ++init(Properties properties) ++acquire(String key, long timeout) ++release(String key) ++subscribe(String key, SubscribeListener listener) ++unSubscribe(String key) ++getActiveServerList() ++close() +} +class Registry { +<> ++init(Properties properties) ++acquire(String key, long timeout) ++release(String key) ++subscribe(String key, SubscribeListener listener) ++unSubscribe(String key) ++getActiveServerList() ++close() +} +MysqlRegistry --> Registry : "实现" +MysqlRegistry --> MysqlMutex : "使用" +MysqlRegistry --> MysqlServerStateManager : "使用" +``` + +**图源** +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java#L29-L106) +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java#L26-L44) + +**本节源码** +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java#L29-L106) + +## MysqlServerStateManager服务状态管理 + +MysqlServerStateManager负责管理服务实例的状态,包括服务注册、心跳更新和故障检测。该组件在初始化时创建定时任务,每2秒执行一次心跳更新,每10秒执行一次服务状态检查。服务注册时,首先检查服务是否已存在,若存在则更新更新时间,否则插入新记录。心跳检测通过比较update_time字段与当前时间的差值来判断服务是否存活,超过20秒未更新的服务被视为已下线。故障剔除机制会定期清理失效服务,并通知订阅者服务状态变化。 + +```mermaid +sequenceDiagram +participant Server as "服务实例" +participant StateManager as "MysqlServerStateManager" +participant DB as "MySQL数据库" +Server->>StateManager : 启动 +StateManager->>StateManager : 创建心跳任务(2秒) +StateManager->>StateManager : 创建检查任务(10秒) +StateManager->>DB : 插入/更新服务记录 +loop 心跳检测 +StateManager->>DB : 更新update_time +end +loop 状态检查 +StateManager->>DB : 查询所有服务 +DB-->>StateManager : 返回服务列表 +StateManager->>StateManager : 检查超时服务 +alt 发现超时服务 +StateManager->>DB : 删除超时记录 +StateManager->>StateManager : 通知订阅者 +end +end +``` + +**图源** +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java#L33-L257) + +**本节源码** +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java#L33-L257) + +## 分布式锁实现原理 + +MySQL注册中心通过MysqlMutex和RegistryLock实现分布式锁机制,确保集群环境下关键操作的互斥性。MysqlMutex是分布式锁的主要实现类,通过dv_registry_lock表存储锁信息。获取锁时尝试插入记录,利用数据库的唯一约束防止重复获取;释放锁时删除对应记录。RegistryLock类封装了锁的元数据,包括锁键、持有者和更新时间。锁的持有时间通过定时任务定期更新,防止锁过期。该实现利用数据库的行级锁和事务特性,确保了锁的可靠性和一致性。 + +```mermaid +classDiagram +class MysqlMutex { +-Connection connection +-Properties properties +-ServerInfo serverInfo +-ConcurrentHashMap lockHoldMap ++acquire(String lockKey, long time) ++release(String lockKey) ++close() +} +class RegistryLock { +-String lockKey +-String lockOwner +-Timestamp updateTime +} +class LockTermRefreshTask { +-Map lockHoldMap ++run() +} +MysqlMutex --> RegistryLock : "持有" +MysqlMutex --> LockTermRefreshTask : "创建" +LockTermRefreshTask --> RegistryLock : "更新" +``` + +**图源** +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java#L36-L218) +- [RegistryLock.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\RegistryLock.java#L28-L36) + +**本节源码** +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java#L36-L218) +- [RegistryLock.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\RegistryLock.java#L28-L36) + +## 心跳检测与故障剔除 + +心跳检测和故障剔除是MySQL注册中心的核心功能,确保服务列表的实时性和准确性。心跳检测通过定时更新服务实例的update_time字段实现,频率为每2秒一次。故障剔除机制每10秒执行一次,查询所有服务记录,计算每个服务的最后更新时间与当前时间的差值,超过20秒的服务被视为失效。系统会从数据库中删除失效服务记录,同时从本地缓存中移除,并通过事件通知机制告知订阅者。该机制有效防止了僵尸服务的存在,保证了服务发现的可靠性。 + +```mermaid +flowchart TD +Start([开始]) --> CheckServers["查询所有服务记录"] +CheckServers --> ProcessServer["处理每个服务"] +ProcessServer --> CalcInterval["计算更新间隔"] +CalcInterval --> Timeout{"间隔>20秒?"} +Timeout --> |是| RemoveServer["删除服务记录"] +RemoveServer --> Notify["通知订阅者"] +Notify --> UpdateCache["更新本地缓存"] +Timeout --> |否| CheckOnline["检查是否在线"] +CheckOnline --> End([结束]) +UpdateCache --> End +``` + +**图源** +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java#L212-L244) + +**本节源码** +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java#L212-L244) + +## 数据库表结构设计 + +MySQL注册中心的数据库表结构设计简洁高效,主要包括dv_server和dv_registry_lock两个核心表。dv_server表存储服务实例信息,包含host、port、create_time和update_time字段,通过唯一索引确保服务实例的唯一性。dv_registry_lock表实现分布式锁,包含lock_key、lock_owner、create_time和update_time字段,通过唯一索引保证锁的互斥性。表结构设计充分考虑了查询性能和数据一致性,为注册中心的稳定运行提供了基础保障。 + +```mermaid +erDiagram +dv_server { +int id PK +varchar host UK +int port UK +datetime create_time +datetime update_time +} +dv_registry_lock { +bigint id PK +varchar lock_key UK +varchar lock_owner +datetime create_time +datetime update_time +} +dv_server ||--o{ dv_registry_lock : "服务-锁" +``` + +**图源** +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql#L677-L702) + +**本节源码** +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql#L677-L702) + +## 性能评估与高可用部署 + +MySQL注册中心的性能主要受数据库性能和网络延迟影响。在高并发场景下,频繁的心跳更新可能对数据库造成压力,建议通过调整心跳间隔和连接池配置来优化性能。高可用部署方面,推荐使用MySQL主从复制或集群方案,确保注册中心的高可用性。同时,应配置合理的连接超时和重试机制,应对网络波动。监控方面,建议监控数据库连接数、查询响应时间和锁等待时间等关键指标,及时发现和解决性能瓶颈。 + +**本节源码** +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java#L51-L54) +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java#L55-L62) + +## 配置与使用 + +MySQL注册中心的配置主要通过application.yaml文件完成。在Spring配置文件中,通过激活mysql配置文件来使用MySQL注册中心。配置包括数据库连接信息、驱动类、URL、用户名和密码等。使用时,服务实例通过MysqlRegistry接口进行注册和发现,通过acquire和release方法获取和释放分布式锁。建议在生产环境中配置连接池和连接超时参数,确保系统的稳定性和可靠性。 + +```mermaid +flowchart LR +Config[配置文件] --> |application.yaml| Registry[MysqlRegistry] +Registry --> |连接| MySQL[MySQL数据库] +MySQL --> |存储| ServerTable[dv_server] +MySQL --> |存储| LockTable[dv_registry_lock] +Client[服务实例] --> |注册| Registry +Client --> |获取锁| Registry +``` + +**图源** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L84-L96) + +**本节源码** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L84-L96) + +## 总结 + +DataVines MySQL注册中心通过简洁而高效的设计,实现了可靠的服务注册与发现功能。基于MySQL数据库的存储方案,充分利用了关系型数据库的ACID特性,确保了数据的一致性和可靠性。心跳检测和故障剔除机制保证了服务列表的实时性,分布式锁实现了集群环境下的互斥操作。该注册中心适用于对数据一致性要求较高的场景,为分布式系统提供了稳定的服务治理基础。未来可进一步优化性能,支持更多数据库类型,提升系统的灵活性和可扩展性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/ZooKeeper\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/ZooKeeper\345\256\236\347\216\260.md" new file mode 100644 index 00000000..33ae04d2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/ZooKeeper\345\256\236\347\216\260.md" @@ -0,0 +1,393 @@ +# ZooKeeper实现 + + +**本文档引用文件** +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java) +- [DefaultEnsembleProvider.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/DefaultEnsembleProvider.java) +- [ZooKeeperRegistry.java](file://datavines-registry/ datavines-registry-plugins/ datavines-registry-zookeeper/ src/main/java/io/ datavines/registry/plugin/ZooKeeperRegistry.java) +- [Registry.java](file://datavines-registry/ datavines-registry-api/ src/main/java/io/ datavines/registry/api/Registry.java) +- [ConnectionListener.java](file://datavines-registry/ datavines-registry-api/ src/main/java/io/ datavines/registry/api/ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry/ datavines-registry-api/ src/main/java/io/ datavines/registry/api/SubscribeListener.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细描述了DataVines中基于ZooKeeper的服务注册与发现机制。文档涵盖了ZooKeeper客户端封装、服务注册、心跳检测、故障剔除、连接状态监听等核心功能的实现原理。通过分析ZooKeeperRegistry、ZooKeeperClient等关键组件,深入解析了临时节点的使用方式、会话管理机制以及ZooKeeper配置参数的调优建议。 + +## 项目结构 +DataVines的ZooKeeper注册中心实现主要分布在两个模块中:`datavines-common`和`datavines-registry-plugins`。`datavines-common`模块提供了ZooKeeper客户端的基础封装,而`datavines-registry-plugins`模块实现了具体的注册中心功能。 + +```mermaid +graph TD +subgraph "datavines-common" +ZooKeeperClient["ZooKeeperClient
客户端封装"] +ZooKeeperConfig["ZooKeeperConfig
配置类"] +DefaultEnsembleProvider["DefaultEnsembleProvider
集群提供者"] +end +subgraph "datavines-registry-plugins" +ZooKeeperRegistry["ZooKeeperRegistry
注册中心实现"] +end +subgraph "datavines-registry-api" +Registry["Registry
注册中心接口"] +ConnectionListener["ConnectionListener
连接监听器"] +SubscribeListener["SubscribeListener
订阅监听器"] +end +ZooKeeperClient --> ZooKeeperRegistry +ZooKeeperConfig --> ZooKeeperClient +DefaultEnsembleProvider --> ZooKeeperClient +Registry --> ZooKeeperRegistry +ConnectionListener --> ZooKeeperRegistry +SubscribeListener --> ZooKeeperRegistry +``` + +**图示来源** +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java) +- [DefaultEnsembleProvider.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/DefaultEnsembleProvider.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) + +**本节来源** +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +## 核心组件 +DataVines的ZooKeeper注册中心实现包含几个核心组件:ZooKeeperClient负责与ZooKeeper服务器的底层通信,ZooKeeperConfig用于配置连接参数,ZooKeeperRegistry实现了服务注册与发现的具体逻辑。 + +**本节来源** +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +## 架构概述 +DataVines的ZooKeeper注册中心采用分层架构设计,上层为注册中心接口,中层为具体实现,底层为ZooKeeper客户端封装。这种设计实现了关注点分离,提高了代码的可维护性和可扩展性。 + +```mermaid +graph TD +A[应用层] --> B[注册中心接口] +B --> C[ZooKeeper注册中心实现] +C --> D[ZooKeeper客户端封装] +D --> E[ZooKeeper服务器] +style A fill:#f9f,stroke:#333 +style B fill:#bbf,stroke:#333 +style C fill:#f96,stroke:#333 +style D fill:#9f9,stroke:#333 +style E fill:#999,stroke:#333 +classDef layer fill:#eee,stroke:#999,stroke-width:1px; +class A,B,C,D,E layer; +``` + +**图示来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) + +## 详细组件分析 + +### ZooKeeper客户端封装分析 +ZooKeeperClient类是DataVines对Curator Framework的封装,提供了单例模式的ZooKeeper客户端实例。该类负责管理与ZooKeeper服务器的连接,提供基本的CRUD操作。 + +```mermaid +classDiagram +class ZooKeeperClient { +-Logger logger +-volatile CuratorFramework client ++getInstance() ZooKeeperClient ++buildClient(ZooKeeperConfig) ZooKeeperClient ++get(String) String ++getChildrenKeys(String) String[] ++isExisted(String) boolean ++persist(String, String) void ++update(String, String) void ++persistEphemeral(String, String) void ++persistEphemeral(String, String, boolean) void ++persistEphemeralSequential(String) void ++remove(String) void ++getClient() CuratorFramework ++close() void ++blockAcquireMutex(String) InterProcessMutex ++blockAcquireMutex(String, long) InterProcessMutex +} +class ZooKeeperConfig { +-String serverList +-int baseSleepTimeMs +-int maxSleepMs +-int maxRetries +-int sessionTimeoutMs +-int connectionTimeoutMs +-String digest ++ZooKeeperConfig() ++ZooKeeperConfig(String) ++ZooKeeperConfig(String, int, int, int) ++getServerList() String ++setServerList(String) void ++getBaseSleepTimeMs() int ++setBaseSleepTimeMs(int) void ++getMaxSleepMs() int ++setMaxSleepMs(int) void ++getMaxRetries() int ++setMaxRetries(int) void ++getSessionTimeoutMs() int ++setSessionTimeoutMs(int) void ++getConnectionTimeoutMs() int ++setConnectionTimeoutMs(int) void ++getDigest() String ++setDigest(String) void +} +class DefaultEnsembleProvider { +-String serverList ++DefaultEnsembleProvider(String) ++start() void ++getConnectionString() String ++close() void ++setConnectionString(String) void ++updateServerListEnabled() boolean +} +ZooKeeperClient --> ZooKeeperConfig : "使用" +ZooKeeperClient --> DefaultEnsembleProvider : "使用" +ZooKeeperClient --> CuratorFramework : "封装" +``` + +**图示来源** +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java#L39-L224) +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java#L19-L104) +- [DefaultEnsembleProvider.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/DefaultEnsembleProvider.java#L23-L55) + +**本节来源** +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java) +- [DefaultEnsembleProvider.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/DefaultEnsembleProvider.java) + +### ZooKeeper注册中心实现分析 +ZooKeeperRegistry类实现了Registry接口,提供了基于ZooKeeper的服务注册与发现功能。该类利用ZooKeeper的临时节点特性来实现服务的心跳检测和故障剔除。 + +```mermaid +classDiagram +class ZooKeeperRegistry { +-ZooKeeperClient zooKeeperClient +-Map~String, ConnectionListener~ connectionListeners +-Map~String, SubscribeListener~ subscribeListeners ++init(Properties) void ++register(ServerInfo) void ++unregister(ServerInfo) void ++subscribe(String, SubscribeListener) void ++unsubscribe(String, SubscribeListener) void ++query(String) ServerInfo[] ++close() void ++getConnectionStatus() ConnectionStatus ++addConnectionListener(ConnectionListener) void ++removeConnectionListener(ConnectionListener) void +} +class Registry { +<> ++init(Properties) void ++register(ServerInfo) void ++unregister(ServerInfo) void ++subscribe(String, SubscribeListener) void ++unsubscribe(String, SubscribeListener) void ++query(String) ServerInfo[] ++close() void ++getConnectionStatus() ConnectionStatus ++addConnectionListener(ConnectionListener) void ++removeConnectionListener(ConnectionListener) void +} +class ConnectionListener { +<> ++onConnected() void ++onDisconnected() void +} +class SubscribeListener { +<> ++onDataChanged(String, ServerInfo[]) void +} +class ServerInfo { +-String host +-int port +-String url +-Map~String, String~ properties ++getHost() String ++setHost(String) void ++getPort() int ++setPort(int) void ++getUrl() String ++setUrl(String) void ++getProperties() Map~String, String~ ++setProperties(Map~String, String~) void +} +ZooKeeperRegistry --> Registry : "实现" +ZooKeeperRegistry --> ZooKeeperClient : "依赖" +ZooKeeperRegistry --> ConnectionListener : "管理" +ZooKeeperRegistry --> SubscribeListener : "管理" +ZooKeeperRegistry --> ServerInfo : "使用" +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +### 服务注册与发现流程分析 +当服务启动时,会通过ZooKeeperRegistry注册自身信息。注册过程使用临时节点,确保服务下线时能自动从注册中心移除。 + +```mermaid +sequenceDiagram +participant Service as "服务实例" +participant Registry as "ZooKeeperRegistry" +participant Client as "ZooKeeperClient" +participant ZK as "ZooKeeper服务器" +Service->>Registry : register(serverInfo) +Registry->>Client : persistEphemeral(path, serverInfo) +Client->>ZK : CREATE(path, EPHEMERAL) +ZK-->>Client : SUCCESS +Client-->>Registry : SUCCESS +Registry-->>Service : 注册成功 +Note over Service,ZK : 服务注册完成 +Service->>Registry : unregister(serverInfo) +Registry->>Client : remove(path) +Client->>ZK : DELETE(path) +ZK-->>Client : SUCCESS +Client-->>Registry : SUCCESS +Registry-->>Service : 注销成功 +Note over Service,ZK : 服务注销完成 +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L50-L80) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java#L153-L180) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) + +### 心跳检测与故障剔除机制分析 +ZooKeeper的临时节点特性是实现心跳检测和故障剔除的核心。当服务与ZooKeeper的会话断开时,临时节点会自动被删除,从而实现故障服务的自动剔除。 + +```mermaid +flowchart TD +A[服务启动] --> B[创建临时节点] +B --> C{ZooKeeper会话保持} +C --> |是| D[节点持续存在] +C --> |否| E[会话超时] +E --> F[ZooKeeper自动删除临时节点] +F --> G[服务从注册中心移除] +D --> H[服务正常运行] +H --> C +style A fill:#f9f,stroke:#333 +style B fill:#9f9,stroke:#333 +style C fill:#ff9,stroke:#333 +style D fill:#9f9,stroke:#333 +style E fill:#f96,stroke:#333 +style F fill:#f96,stroke:#333 +style G fill:#f96,stroke:#333 +style H fill:#9f9,stroke:#333 +``` + +**图示来源** +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java#L153-L163) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +**本节来源** +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +### 连接状态监听处理分析 +ZooKeeperConnectionStateListener负责监听ZooKeeper客户端的连接状态变化,并通知注册的ConnectionListener。 + +```mermaid +sequenceDiagram +participant Client as "ZooKeeperClient" +participant Listener as "ConnectionStateListener" +participant Registry as "ZooKeeperRegistry" +participant App as "应用程序" +Client->>Listener : 连接状态变化 +Listener->>Registry : 通知状态变化 +Registry->>Registry : 遍历connectionListeners +loop 每个监听器 +Registry->>Listener : onConnected()/onDisconnected() +end +Listener->>App : 处理连接状态变化 +Note over Client,App : 连接状态监听流程 +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java) + +## 依赖分析 +DataVines的ZooKeeper注册中心实现依赖于Curator Framework作为ZooKeeper的客户端库,同时遵循SPI机制,允许通过配置切换不同的注册中心实现。 + +```mermaid +graph TD +A[ZooKeeperRegistry] --> B[Curator Framework] +A --> C[ZooKeeperClient] +C --> D[ZooKeeperConfig] +C --> E[DefaultEnsembleProvider] +A --> F[Registry API] +F --> G[ConnectionListener] +F --> H[SubscribeListener] +style A fill:#f96,stroke:#333 +style B fill:#999,stroke:#333 +style C fill:#9f9,stroke:#333 +style D fill:#9f9,stroke:#333 +style E fill:#9f9,stroke:#333 +style F fill:#bbf,stroke:#333 +style G fill:#bbf,stroke:#333 +style H fill:#bbf,stroke:#333 +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) + +## 性能考虑 +在使用ZooKeeper注册中心时,需要注意以下性能调优点: + +1. **会话超时配置**:合理设置sessionTimeoutMs参数,避免过短导致频繁重连,过长导致故障检测延迟。 +2. **连接重试策略**:通过baseSleepTimeMs、maxSleepMs和maxRetries参数配置指数退避重试策略。 +3. **连接超时**:设置合理的connectionTimeoutMs,避免在ZooKeeper不可用时长时间阻塞。 +4. **批量操作**:对于大量节点操作,考虑使用事务或批量API减少网络开销。 + +**本节来源** +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) + +## 故障排除指南 +当遇到ZooKeeper注册中心相关问题时,可以参考以下排查步骤: + +1. **连接问题**:检查ZooKeeper服务器地址和端口配置是否正确。 +2. **认证问题**:如果启用了ACL,确保digest配置正确。 +3. **会话超时**:监控ZooKeeper客户端日志,查看是否有频繁的会话超时。 +4. **节点冲突**:确保服务注册的路径唯一,避免节点冲突。 + +**本节来源** +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +## 结论 +DataVines的ZooKeeper注册中心实现通过封装Curator Framework,提供了稳定可靠的服务注册与发现功能。利用ZooKeeper的临时节点特性,实现了自动的心跳检测和故障剔除机制。通过清晰的接口设计和SPI机制,保证了系统的可扩展性和灵活性。合理的配置参数和性能调优建议有助于在生产环境中稳定运行。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/\345\256\242\346\210\267\347\253\257\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/\345\256\242\346\210\267\347\253\257\347\256\241\347\220\206.md" new file mode 100644 index 00000000..b53afe23 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/\345\256\242\346\210\267\347\253\257\347\256\241\347\220\206.md" @@ -0,0 +1,247 @@ +# 客户端管理 + + +**本文档引用的文件** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) + + +## 目录 +1. [简介](#简介) +2. [注册中心客户端统一管理](#注册中心客户端统一管理) +3. [Register注解与自动注册机制](#register注解与自动注册机制) +4. [客户端生命周期管理](#客户端生命周期管理) +5. [多注册中心配置支持](#多注册中心配置支持) +6. [客户端配置参数说明](#客户端配置参数说明) +7. [连接池管理建议](#连接池管理建议) + +## 简介 +DataVines注册中心客户端管理机制提供了一套完整的注册中心实例管理方案,通过RegistryHolder统一管理注册中心客户端实例,支持多种注册中心实现(如MySQL、ZooKeeper),并提供自动注册、连接管理和资源释放等核心功能。本文档详细说明了注册中心客户端的管理机制、生命周期、配置策略和最佳实践。 + +## 注册中心客户端统一管理 + +DataVines通过RegistryHolder类实现注册中心客户端实例的统一管理。RegistryHolder作为注册中心客户端的全局持有者,负责注册中心实例的创建、获取和生命周期管理。该机制基于SPI(Service Provider Interface)扩展机制,允许系统动态加载不同类型的注册中心实现。 + +RegistryHolder通过单例模式确保全局唯一性,所有组件通过RegistryHolder获取注册中心客户端实例,避免了重复创建和资源浪费。当需要访问注册中心时,系统通过RegistryHolder.getRegistry()方法获取相应的注册中心实例,该方法根据配置的注册中心类型返回具体的实现。 + +注册中心接口(Registry)定义了统一的操作契约,包括初始化、获取锁、订阅、获取活跃服务器列表和关闭连接等核心方法。不同的注册中心实现(如MysqlRegistry和ZooKeeperRegistry)都实现了这个接口,确保了API的一致性。 + +```mermaid +classDiagram +class Registry { +<> ++init(Properties) void ++acquire(String, long) boolean ++release(String) boolean ++subscribe(String, SubscribeListener) void ++unSubscribe(String) void ++addConnectionListener(ConnectionListener) void ++getActiveServerList() ServerInfo[] ++close() void +} +class RegistryHolder { +-static Registry registry +-static Properties properties ++getRegistry() Registry ++init(Properties) void ++close() void +} +class MysqlRegistry { +-MysqlMutex mysqlMutex +-MysqlServerStateManager mysqlServerStateManager ++init(Properties) void ++acquire(String, long) boolean ++release(String) boolean ++close() void +} +class ZooKeeperRegistry { +-CuratorFramework client +-String rootPath ++init(Properties) void ++acquire(String, long) boolean ++release(String) boolean ++close() void +} +Registry <|-- MysqlRegistry +Registry <|-- ZooKeeperRegistry +RegistryHolder --> Registry : "持有" +``` + +**图示来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) + +**本节来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L25-L43) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) + +## Register注解与自动注册机制 + +DataVines通过Register注解实现服务的自动注册功能。Register注解用于标记需要注册到注册中心的组件或服务,系统在启动时会扫描带有该注解的类,并自动将其注册到配置的注册中心中。 + +自动注册机制基于Java的SPI扩展机制和反射技术实现。系统通过PluginLoader加载所有实现了特定接口的插件,并检查这些类是否带有Register注解。如果发现带有Register注解的类,系统会自动创建该类的实例并将其注册信息写入注册中心。 + +Register注解通常包含注册路径、服务名称、权重等元数据信息,这些信息用于在注册中心中创建相应的节点。注册中心会根据这些信息创建持久节点或临时节点,具体取决于服务的类型和需求。 + +```mermaid +sequenceDiagram +participant 应用启动 as 应用启动 +participant PluginLoader as PluginLoader +participant RegisterScanner as RegisterScanner +participant RegistryHolder as RegistryHolder +participant Registry as 注册中心 +应用启动->>PluginLoader : 加载所有插件 +PluginLoader->>PluginLoader : 扫描META-INF/services目录 +PluginLoader->>RegisterScanner : 获取所有实现类 +RegisterScanner->>RegisterScanner : 检查Register注解 +RegisterScanner->>RegisterScanner : 收集带注解的类 +RegisterScanner->>RegistryHolder : 请求注册中心实例 +RegistryHolder->>RegistryHolder : 初始化注册中心 +RegistryHolder-->>RegisterScanner : 返回注册中心实例 +RegisterScanner->>Registry : 执行注册操作 +Registry-->>RegisterScanner : 返回注册结果 +RegisterScanner->>应用启动 : 完成自动注册 +``` + +**图示来源** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) + +**本节来源** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L70-L486) + +## 客户端生命周期管理 + +注册中心客户端的生命周期管理包括初始化、连接管理和资源释放三个主要阶段。RegistryHolder负责协调整个生命周期,确保客户端实例的正确创建和销毁。 + +在初始化阶段,RegistryHolder根据配置的注册中心类型(通过配置文件指定)创建相应的注册中心实例。初始化过程包括读取配置属性、建立网络连接、创建必要的数据结构等。对于MySQL注册中心,初始化会建立数据库连接并创建必要的表结构;对于ZooKeeper注册中心,初始化会建立ZooKeeper会话并创建根路径。 + +连接管理阶段涉及连接的健康检查、重连机制和连接池管理。注册中心客户端会定期检查连接状态,当检测到连接断开时,会自动尝试重新连接。系统还支持连接监听器(ConnectionListener),允许注册回调函数来处理连接状态变化事件。 + +资源释放阶段在系统关闭时执行,RegistryHolder会调用注册中心实例的close()方法,释放所有占用的资源,包括数据库连接、网络会话和内存数据结构。这个过程确保了资源的优雅释放,避免了资源泄漏。 + +```mermaid +flowchart TD +A[客户端生命周期开始] --> B[初始化] +B --> B1[读取配置属性] +B1 --> B2[创建注册中心实例] +B2 --> B3[建立连接] +B3 --> B4[初始化数据结构] +B4 --> C[连接管理] +C --> C1[健康检查] +C1 --> C2{连接正常?} +C2 --> |是| C3[继续服务] +C2 --> |否| C4[尝试重连] +C4 --> C5{重连成功?} +C5 --> |是| C3 +C5 --> |否| C6[触发连接监听器] +C6 --> C7[等待重试] +C7 --> C1 +C --> D[资源释放] +D --> D1[调用close()方法] +D1 --> D2[释放数据库连接] +D2 --> D3[关闭网络会话] +D3 --> D4[清理内存数据] +D4 --> E[客户端生命周期结束] +``` + +**图示来源** +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L28-L42) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L35-L38) + +**本节来源** +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) + +## 多注册中心配置支持 + +DataVines支持多注册中心配置策略,允许系统根据不同的场景和需求选择合适的注册中心实现。这种灵活性通过配置驱动的方式实现,用户可以在配置文件中指定使用的注册中心类型。 + +多注册中心支持基于SPI机制实现,不同的注册中心实现被打包为独立的插件模块。系统通过PluginLoader动态加载这些插件,并根据配置创建相应的实例。这种设计实现了注册中心实现与核心逻辑的解耦,使得添加新的注册中心支持变得简单。 + +配置文件中通过"registry.type"属性指定注册中心类型,可选值包括"mysql"、"zookeeper"等。相应的配置属性(如数据库连接信息或ZooKeeper连接字符串)也会根据注册中心类型进行组织。这种配置策略使得系统可以在不同环境中灵活切换注册中心实现。 + +```mermaid +graph TB +subgraph 配置层 +A[配置文件] --> B[registry.type=mysql] +A --> C[数据库连接配置] +A --> D[registry.type=zookeeper] +A --> E[ZooKeeper连接配置] +end +subgraph 抽象层 +F[Registry接口] --> G[统一API] +end +subgraph 实现层 +H[MysqlRegistry] --> I[MySQL数据库] +J[ZooKeeperRegistry] --> K[ZooKeeper集群] +end +B --> H +D --> J +H --> F +J --> F +C --> H +E --> J +``` + +**图示来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +**本节来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +## 客户端配置参数说明 + +注册中心客户端的配置通过Properties对象传递,包含连接信息、超时设置、重试策略等关键参数。主要配置参数包括: + +- **registry.type**: 注册中心类型,可选值为"mysql"或"zookeeper" +- **db.url**: 数据库连接URL(MySQL注册中心使用) +- **db.username**: 数据库用户名(MySQL注册中心使用) +- **db.password**: 数据库密码(MySQL注册中心使用) +- **zk.connect.string**: ZooKeeper连接字符串(ZooKeeper注册中心使用) +- **session.timeout**: 会话超时时间 +- **connection.timeout**: 连接超时时间 +- **retry.policy**: 重试策略配置 +- **base.path**: 注册中心根路径 + +这些配置参数在系统启动时由RegistryHolder读取,并传递给具体的注册中心实现进行初始化。配置的灵活性使得系统可以适应不同的部署环境和性能要求。 + +**本节来源** +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L35-L38) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +## 连接池管理建议 + +对于基于数据库的注册中心(如MySQL注册中心),建议配置适当的连接池参数以优化性能和资源利用率。关键的连接池管理建议包括: + +1. **连接池大小**: 根据并发需求设置合理的连接池大小,避免过多连接导致数据库压力过大,同时确保有足够的连接处理并发请求。 + +2. **连接超时**: 设置适当的连接超时时间,避免客户端长时间等待连接,影响系统响应性。 + +3. **空闲连接回收**: 配置空闲连接回收策略,定期清理长时间未使用的连接,释放数据库资源。 + +4. **连接验证**: 启用连接验证功能,在从连接池获取连接时检查连接的有效性,避免使用已失效的连接。 + +5. **监控和告警**: 实施连接池监控,跟踪连接使用情况、等待时间和错误率,设置告警阈值及时发现潜在问题。 + +对于ZooKeeper注册中心,虽然不使用传统意义上的连接池,但建议合理配置会话超时和重试策略,确保在网络波动时能够快速恢复连接。 + +**本节来源** +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [ConnectionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ConnectionUtils.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/\346\263\250\345\206\214\344\270\255\345\277\203\346\216\245\345\217\243\350\256\276\350\256\241.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/\346\263\250\345\206\214\344\270\255\345\277\203\346\216\245\345\217\243\350\256\276\350\256\241.md" new file mode 100644 index 00000000..d22873bb --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/\346\263\250\345\206\214\344\270\255\345\277\203\346\216\245\345\217\243\350\256\276\350\256\241.md" @@ -0,0 +1,305 @@ +# 注册中心接口设计 + + +**本文档引用的文件** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java) +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java) +- [Event.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Event.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) + + +## 目录 +1. [引言](#引言) +2. [核心接口契约定义](#核心接口契约定义) +3. [服务注册与注销机制](#服务注册与注销机制) +4. [订阅与监听功能](#订阅与监听功能) +5. [回调接口设计](#回调接口设计) +6. [服务实例数据结构](#服务实例数据结构) +7. [多注册中心实现支持](#多注册中心实现支持) +8. [使用示例与最佳实践](#使用示例与最佳实践) +9. [结论](#结论) + +## 引言 +DataVines注册中心接口为分布式系统提供了统一的服务发现和协调机制。该接口设计遵循SPI(Service Provider Interface)规范,支持多种注册中心实现,如ZooKeeper和MySQL。通过该接口,系统组件可以实现服务注册、发现、订阅和状态监控等功能,确保系统的高可用性和弹性。 + +## 核心接口契约定义 + +DataVines注册中心的核心接口`Registry`定义了服务发现和协调的基本契约。该接口通过`@SPI`注解标记,表明其为服务提供者接口,允许不同的实现插件通过SPI机制进行扩展。 + +```mermaid +classDiagram +class Registry { ++init(Properties properties) void ++acquire(String key, long timeout) boolean ++release(String key) boolean ++subscribe(String key, SubscribeListener listener) void ++unSubscribe(String key) void ++addConnectionListener(ConnectionListener connectionListener) void ++getActiveServerList() ServerInfo[] ++close() void +} +class ServerInfo { +-host String +-serverPort Integer +-createTime Timestamp +-updateTime Timestamp ++getAddr() String +} +class ConnectionListener { ++onUpdate(ConnectionStatus status) void +} +class SubscribeListener { ++notify(Event event) void +} +class Event { +-key String +-value String +-type Type ++builder() EventBuilder +} +class ConnectionStatus { +CONNECTED +RECONNECTED +DISCONNECTED +} +class RegistryException { ++RegistryException(String msg) ++RegistryException(String msg, Throwable cause) +} +Registry <|-- ZooKeeperRegistry +Registry <|-- MysqlRegistry +Registry --> ServerInfo +Registry --> ConnectionListener +Registry --> SubscribeListener +SubscribeListener --> Event +ConnectionListener --> ConnectionStatus +``` + +**图示来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java) +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java) +- [Event.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Event.java) + +**本节来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L26-L43) + +## 服务注册与注销机制 + +注册中心接口提供了服务注册和注销的核心功能。`acquire`方法用于获取分布式锁或注册服务实例,`release`方法用于释放锁或注销服务。这些方法确保了在分布式环境中的互斥访问和资源管理。 + +服务注册通常在系统启动时完成,通过`acquire`方法将服务实例信息写入注册中心。注册信息包括服务地址、端口和时间戳等元数据。当服务实例正常关闭时,应调用`release`方法清理注册信息,实现优雅的服务注销。 + +```mermaid +sequenceDiagram +participant 服务实例 +participant 注册中心 +participant 数据存储 +服务实例->>注册中心 : acquire(key, timeout) +注册中心->>数据存储 : 检查键是否存在 +数据存储-->>注册中心 : 返回检查结果 +注册中心->>数据存储 : 创建持久节点/记录 +数据存储-->>注册中心 : 创建成功 +注册中心-->>服务实例 : 返回true +服务实例->>注册中心 : release(key) +注册中心->>数据存储 : 删除节点/记录 +数据存储-->>注册中心 : 删除成功 +注册中心-->>服务实例 : 返回true +``` + +**图示来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L30-L32) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +**本节来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L30-L32) + +## 订阅与监听功能 + +注册中心接口提供了基于发布-订阅模式的服务发现机制。`subscribe`方法允许客户端订阅特定的键路径,当该路径下的数据发生变化时,注册中心会通过`SubscribeListener`回调通知订阅者。 + +这种机制对于实现服务发现特别有用。例如,客户端可以订阅服务列表的路径,当有新的服务实例注册或现有实例注销时,会收到相应的事件通知,从而及时更新本地的服务列表缓存。 + +```mermaid +flowchart TD +A[客户端] --> B[调用subscribe方法] +B --> C{注册中心} +C --> D[创建TreeCache监听] +D --> E[监听节点变化] +E --> F{节点事件类型} +F --> |ADD| G[创建Event对象] +F --> |UPDATE| G +F --> |REMOVE| G +G --> H[调用SubscribeListener.notify] +H --> I[客户端处理事件] +``` + +**图示来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L34-L36) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + +**本节来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L34-L36) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java#L19-L21) + +## 回调接口设计 + +注册中心接口定义了两个重要的回调接口:`ConnectionListener`和`SubscribeListener`,用于实现异步事件通知。 + +`ConnectionListener`接口用于监听注册中心连接状态的变化。当与注册中心的连接建立、重新连接或断开时,会调用`onUpdate`方法并传入相应的`ConnectionStatus`枚举值。这对于实现连接状态监控和故障恢复机制非常重要。 + +`SubscribeListener`接口用于处理订阅路径下的数据变更事件。当监听的节点发生添加、更新或删除操作时,会创建相应的`Event`对象并通过`notify`方法通知监听器。`Event`类包含了事件的键、值和类型信息,使监听器能够根据事件类型执行相应的业务逻辑。 + +```mermaid +classDiagram +class Event { ++key String ++value String ++type Type ++EventBuilder builder() +} +class EventBuilder { ++key(String key) EventBuilder ++value(String value) EventBuilder ++type(Type type) EventBuilder ++build() Event +} +class Type { +ADD +UPDATE +REMOVE +} +EventBuilder --> Event : 构建 +``` + +**图示来源** +- [Event.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Event.java) +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java) + +**本节来源** +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java#L19-L21) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java#L19-L21) +- [Event.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Event.java#L19-L105) + +## 服务实例数据结构 + +`ServerInfo`类定义了服务实例的核心数据结构,包含了服务发现所需的关键信息。该类使用Lombok注解简化了代码,自动生成getter、setter、toString等方法。 + +`ServerInfo`包含以下主要属性: +- `host`:服务实例的主机地址 +- `serverPort`:服务实例的端口号 +- `createTime`:服务创建时间戳 +- `updateTime`:服务更新时间戳 + +此外,`ServerInfo`还提供了一个便捷的`getAddr`方法,用于获取主机和端口的组合字符串,这在服务调用时非常有用。 + +```mermaid +classDiagram +class ServerInfo { +-host String +-serverPort Integer +-createTime Timestamp +-updateTime Timestamp ++ServerInfo(String host, Integer serverPort) ++getAddr() String +} +``` + +**图示来源** +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java) + +**本节来源** +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java#L30-L48) + +## 多注册中心实现支持 + +DataVines注册中心接口通过SPI机制支持多种注册中心实现。目前提供了ZooKeeper和MySQL两种实现,分别位于`datavines-registry-plugins`模块中。 + +`ZooKeeperRegistry`实现了基于ZooKeeper的注册中心功能,利用ZooKeeper的临时节点特性实现服务的自动发现和故障检测。当服务实例与ZooKeeper的会话断开时,其创建的临时节点会自动删除,从而实现服务的自动注销。 + +`MysqlRegistry`实现了基于MySQL数据库的注册中心功能,使用数据库表来存储服务实例信息。通过数据库的行级锁机制实现分布式锁功能,确保服务注册的互斥性。 + +SPI配置文件`META-INF/plugins/io.datavines.registry.api.Registry`定义了可用的实现: +``` +zookeeper=io.datavines.registry.plugin.ZooKeeperRegistry +mysql=io.datavines.registry.plugin.MysqlRegistry +``` + +这种设计使得系统可以根据实际需求选择合适的注册中心实现,提高了系统的灵活性和可移植性。 + +```mermaid +graph TB +subgraph "注册中心接口" +Registry[Registry 接口] +end +subgraph "实现" +ZooKeeperRegistry[ZooKeeperRegistry] +MysqlRegistry[MysqlRegistry] +end +subgraph "存储" +ZooKeeper[(ZooKeeper)] +MySQL[(MySQL)] +end +Registry --> ZooKeeperRegistry +Registry --> MysqlRegistry +ZooKeeperRegistry --> ZooKeeper +MysqlRegistry --> MySQL +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [io.datavines.registry.api.Registry](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/resources/META-INF/plugins/io.datavines.registry.api.Registry) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L43-L53) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L29-L38) + +## 使用示例与最佳实践 + +在DataVines系统中,注册中心的使用通常遵循以下模式: + +1. **初始化**:在系统启动时,通过`init`方法初始化注册中心,传入必要的配置属性。 +2. **服务注册**:调用`acquire`方法注册服务实例,通常使用服务地址作为键。 +3. **订阅服务**:调用`subscribe`方法订阅感兴趣的服务路径,注册相应的监听器。 +4. **状态监控**:添加`ConnectionListener`以监控注册中心的连接状态。 +5. **资源清理**:在系统关闭时,调用`close`方法释放资源。 + +最佳实践包括: +- 使用有意义的键路径组织服务实例,便于管理和发现 +- 为`acquire`操作设置合理的超时时间,避免无限等待 +- 在`SubscribeListener`的`notify`方法中实现幂等性,以处理可能的重复事件 +- 及时处理连接状态变化事件,实现故障恢复机制 +- 在系统关闭时确保正确调用`release`和`close`方法,避免资源泄漏 + +```mermaid +flowchart TD +A[系统启动] --> B[初始化注册中心] +B --> C[注册服务实例] +C --> D[订阅服务列表] +D --> E[添加连接监听器] +E --> F[正常运行] +F --> G{系统关闭?} +G --> |是| H[注销服务实例] +H --> I[关闭注册中心] +I --> J[系统退出] +G --> |否| F +``` + +**图示来源** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) + +**本节来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) + +## 结论 +DataVines注册中心接口设计简洁而强大,通过定义清晰的契约和回调机制,实现了灵活的服务发现和协调功能。接口的SPI设计模式支持多种注册中心实现,使系统能够适应不同的部署环境和需求。通过合理使用服务注册、订阅和监听功能,可以构建高可用、弹性的分布式系统。在实际应用中,应遵循最佳实践,确保系统的稳定性和可靠性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266.md" new file mode 100644 index 00000000..f86492c6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266/\346\263\250\345\206\214\344\270\255\345\277\203\346\234\272\345\210\266.md" @@ -0,0 +1,289 @@ +# 注册中心机制 + + +**本文档引用的文件** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java) + + +## 目录 +1. [引言](#引言) +2. [注册中心接口设计](#注册中心接口设计) +3. [ZooKeeper实现机制](#zookeeper实现机制) +4. [MySQL实现机制](#mysql实现机制) +5. [服务注册与发现流程](#服务注册与发现流程) +6. [心跳检测与故障剔除](#心跳检测与故障剔除) +7. [RegistryHolder客户端管理](#registryholder客户端管理) +8. [分布式锁实现原理](#分布式锁实现原理) +9. [注册中心选型建议](#注册中心选型建议) +10. [性能优化方案](#性能优化方案) + +## 引言 +DataVines注册中心机制为分布式系统提供了服务注册与发现的核心功能。该机制通过统一的Registry接口抽象,支持ZooKeeper和MySQL两种注册中心实现方式,满足不同场景下的高可用和性能需求。注册中心负责管理服务实例的生命周期,包括服务注册、心跳维持、故障检测和分布式锁管理等功能,为DataVines集群的稳定运行提供基础保障。 + +## 注册中心接口设计 +DataVines注册中心采用接口抽象设计,定义了统一的Registry接口,包含服务注册、发现、分布式锁和事件监听等核心功能。 + +```mermaid +classDiagram +class Registry { ++init(Properties properties) ++acquire(String key, long timeout) ++release(String key) ++subscribe(String key, SubscribeListener listener) ++unSubscribe(String key) ++addConnectionListener(ConnectionListener connectionListener) ++getActiveServerList() ++close() +} +class ServerInfo { ++String host ++Integer serverPort ++Timestamp createTime ++Timestamp updateTime ++getAddr() +} +class Event { ++String key ++String value ++Type type ++EventBuilder builder() +} +class SubscribeListener { ++notify(Event event) +} +class ConnectionListener { ++onUpdate(ConnectionStatus status) +} +Registry <|-- ZooKeeperRegistry +Registry <|-- MysqlRegistry +Event "1" --> "1" SubscribeListener +ConnectionListener "1" --> "1" Registry +``` + +**图示来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java) +- [Event.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Event.java) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java) +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java) + +**本节来源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L26-L42) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java#L30-L48) + +## ZooKeeper实现机制 +ZooKeeper注册中心实现基于Curator框架,利用ZooKeeper的临时节点特性实现服务注册与发现,通过TreeCache实现事件监听,使用InterProcessMutex实现分布式锁。 + +```mermaid +sequenceDiagram +participant Server as 服务实例 +participant ZKRegistry as ZooKeeperRegistry +participant ZooKeeper as ZooKeeper集群 +participant Listener as 事件监听器 +Server->>ZKRegistry : init(properties) +ZKRegistry->>ZooKeeper : 创建CuratorFramework客户端 +ZKRegistry->>ZooKeeper : 创建临时节点(服务注册) +Server->>ZKRegistry : subscribe(key, listener) +ZKRegistry->>ZooKeeper : 创建TreeCache监听 +ZKRegistry->>Listener : 通知服务变更事件 +Server->>ZKRegistry : acquire(key, timeout) +ZKRegistry->>ZooKeeper : 创建InterProcessMutex锁 +ZKRegistry-->>Server : 获取锁结果 +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L43-L241) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java#L39-L224) +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java#L19-L105) + +## MySQL实现机制 +MySQL注册中心实现基于关系型数据库,通过数据库表记录服务实例信息和锁状态,使用定时任务实现心跳检测和故障剔除。 + +```mermaid +erDiagram +dv_server { +varchar host PK +int port PK +timestamp create_time +timestamp update_time +} +dv_registry_lock { +varchar lock_key PK +varchar lock_owner +timestamp update_time +} +dv_server ||--o{ dv_registry_lock : "服务实例与锁" +``` + +**图示来源** +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java) + +**本节来源** +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L29-L107) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L36-L218) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L33-L257) + +## 服务注册与发现流程 +DataVines注册中心的服务注册与发现流程包括初始化、注册、订阅和获取活跃服务列表等关键步骤。 + +```mermaid +flowchart TD +Start([服务启动]) --> Init["初始化注册中心"] +Init --> Register["注册服务实例"] +Register --> Subscribe["订阅服务变更"] +Subscribe --> GetActive["获取活跃服务列表"] +GetActive --> End([服务发现完成]) +subgraph "ZooKeeper实现" +Register --> ZKCreate["创建临时节点"] +Subscribe --> ZKTreeCache["创建TreeCache监听"] +GetActive --> ZKChildren["获取子节点列表"] +end +subgraph "MySQL实现" +Register --> MysqlInsert["插入dv_server表"] +Subscribe --> MysqlSchedule["启动定时任务"] +GetActive --> MysqlQuery["查询dv_server表"] +end +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L56-L74) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L36-L50) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L191-L205) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L200-L210) + +## 心跳检测与故障剔除 +注册中心通过心跳机制维持服务实例的活跃状态,并在检测到故障时及时剔除失效节点。 + +```mermaid +sequenceDiagram +participant Server as 服务实例 +participant Manager as 服务器状态管理器 +participant DB as 数据库 +loop 心跳检测 +Server->>Manager : 定时更新update_time +Manager->>DB : 执行UPDATE语句 +DB-->>Manager : 更新成功 +Manager-->>Server : 心跳成功 +end +loop 故障检测 +Manager->>DB : 查询所有服务实例 +DB-->>Manager : 返回服务列表 +Manager->>Manager : 计算心跳超时 +Manager->>Manager : 剔除超时服务 +Manager->>Listener : 通知服务下线事件 +end +``` + +**图示来源** +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) + +**本节来源** +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L51-L54) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L212-L228) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L231-L244) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L73-L130) + +## RegistryHolder客户端管理 +RegistryHolder采用单例模式管理注册中心客户端实例,确保系统中只有一个注册中心连接。 + +```mermaid +classDiagram +class RegistryHolder { +-static Registry INSTANCE +-static final Object LOCK ++getRegistry() ++initRegistry(Properties properties) +} +RegistryHolder --> Registry : "持有" +Registry <|-- ZooKeeperRegistry +Registry <|-- MysqlRegistry +``` + +**图示来源** +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) + +**本节来源** +- [RegistryHolder.java](file://datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java) + +## 分布式锁实现原理 +DataVines注册中心提供了两种分布式锁实现:基于ZooKeeper的InterProcessMutex和基于MySQL的乐观锁机制。 + +```mermaid +flowchart TD +Start([尝试获取锁]) --> CheckType["判断注册中心类型"] +CheckType --> |ZooKeeper| ZKLock["使用InterProcessMutex"] +CheckType --> |MySQL| MysqlLock["使用数据库记录"] +ZKLock --> ZKAcquire["acquire(timeout)"] +ZKAcquire --> ZKResult{获取成功?} +ZKResult --> |是| ReturnSuccess["返回true"] +ZKResult --> |否| ZKRetry["等待重试"] +MysqlLock --> MysqlInsert["尝试插入记录"] +MysqlInsert --> MysqlResult{插入成功?} +MysqlResult --> |是| MysqlUpdate["启动定时更新"] +MysqlResult --> |否| MysqlWait["等待并重试"] +MysqlUpdate --> MysqlRefresh["每2秒更新update_time"] +ReturnSuccess --> End([锁获取完成]) +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L77-L112) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L67-L96) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L184-L217) + +## 注册中心选型建议 +根据不同的应用场景和需求,建议如下: + +| 选型维度 | ZooKeeper | MySQL | +|---------|---------|-------| +| **一致性** | 强一致性 | 最终一致性 | +| **可用性** | 高可用 | 依赖数据库可用性 | +| **性能** | 高性能读写 | 受数据库性能限制 | +| **复杂性** | 需要维护ZooKeeper集群 | 利用现有数据库 | +| **适用场景** | 高并发、低延迟场景 | 已有MySQL基础设施 | +| **数据持久化** | 内存+磁盘 | 持久化存储 | +| **扩展性** | 易于水平扩展 | 受单机性能限制 | + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) + +## 性能优化方案 +针对注册中心的性能优化,建议采取以下措施: + +1. **连接池优化**:对MySQL注册中心使用数据库连接池,减少连接创建开销 +2. **缓存机制**:在客户端缓存服务列表,减少对注册中心的频繁查询 +3. **批量操作**:合并多个注册/注销操作,减少网络往返次数 +4. **异步处理**:将非关键操作异步化,提高响应速度 +5. **参数调优**: + - ZooKeeper会话超时时间设置为60秒 + - MySQL心跳检测间隔设置为2秒 + - 故障剔除超时时间设置为20秒 +6. **监控告警**:建立注册中心健康度监控,及时发现和处理异常 +7. **降级策略**:在网络分区等异常情况下,启用本地缓存降级模式 + +**本节来源** +- [ZooKeeperConfig.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperConfig.java#L23-L31) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L51-L54) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L38-L40) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/Quartz\350\260\203\345\272\246\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/Quartz\350\260\203\345\272\246\345\231\250.md" new file mode 100644 index 00000000..1f1bd790 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/Quartz\350\260\203\345\272\246\345\231\250.md" @@ -0,0 +1,209 @@ +# Quartz调度器 + + +**本文档引用的文件** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) +- [CommonTaskScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CommonTaskScheduleServiceImpl.java) + + +## 目录 +1. [引言](#引言) +2. [QuartzExecutors类概述](#quartzexecutors类概述) +3. [定时任务创建与注册](#定时任务创建与注册) +4. [任务删除机制](#任务删除机制) +5. [任务标识符生成](#任务标识符生成) +6. [时区转换逻辑](#时区转换逻辑) +7. [配置最佳实践与性能调优](#配置最佳实践与性能调优) +8. [结论](#结论) + +## 引言 +Quartz调度器是DataVines系统中用于管理定时任务的核心组件。它通过QuartzExecutors类实现对调度器实例的统一管理,支持定时任务的创建、更新、删除等操作。本文档详细阐述了QuartzExecutors类的工作机制,包括任务的创建与注册、删除机制、唯一标识符生成以及时区转换等关键功能。 + +## QuartzExecutors类概述 +QuartzExecutors类是DataVines系统中Quartz调度器的执行器,负责管理调度器实例。该类通过@Autowired注入Scheduler实例,利用ReadWriteLock实现线程安全的读写操作。QuartzExecutors提供了addJob、deleteJob、deleteAllJobs等核心方法,用于管理定时任务的生命周期。 + +**本文档引用的文件** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) + +## 定时任务创建与注册 +### JobDetail与CronTrigger的构建过程 +addJob方法负责创建和注册定时任务。该方法接收Job类和ScheduleJobInfo对象作为参数,首先通过buildJobGroupName和buildJobName方法生成任务组名和任务名,然后构建JobDataMap包含任务相关数据。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant QuartzExecutors as "QuartzExecutors" +participant Scheduler as "Scheduler" +Client->>QuartzExecutors : addJob(clazz, schedule) +QuartzExecutors->>QuartzExecutors : buildJobGroupName(schedule) +QuartzExecutors->>QuartzExecutors : buildJobName(schedule) +QuartzExecutors->>QuartzExecutors : buildDataMap(schedule) +QuartzExecutors->>QuartzExecutors : buildDate(startTime/endTime) +QuartzExecutors->>Scheduler : checkExists(jobKey) +alt 任务已存在 +Scheduler-->>QuartzExecutors : 返回JobDetail +QuartzExecutors->>QuartzExecutors : 更新JobDataMap +QuartzExecutors->>Scheduler : rescheduleJob(triggerKey, cronTrigger) +else 任务不存在 +QuartzExecutors->>Scheduler : addJob(jobDetail) +QuartzExecutors->>Scheduler : scheduleJob(cronTrigger) +end +Scheduler-->>QuartzExecutors : 操作结果 +QuartzExecutors-->>Client : 方法返回 +``` + +**图示来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L74-L148) + +**本节来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L74-L148) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java#L27-L41) + +## 任务删除机制 +### deleteJob方法 +deleteJob方法用于删除指定的定时任务。该方法首先获取任务名称和组名,创建JobKey对象,然后检查任务是否存在。如果任务存在,则调用scheduler.deleteJob(jobKey)进行删除;如果任务不存在,则返回true表示删除成功。 + +### deleteAllJobs方法 +deleteAllJobs方法用于删除指定任务组中的所有任务。该方法通过GroupMatcher.groupEndsWith(jobGroupName)获取任务组中所有任务的JobKey,然后调用scheduler.deleteJobs(jobKeys)批量删除任务。 + +```mermaid +flowchart TD +Start([开始]) --> CheckJobExists["检查任务是否存在"] +CheckJobExists --> |存在| DeleteJob["调用deleteJob删除任务"] +CheckJobExists --> |不存在| ReturnTrue["返回true"] +DeleteJob --> End([结束]) +ReturnTrue --> End +``` + +**图示来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L157-L196) + +**本节来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L157-L196) + +## 任务标识符生成 +### buildJobName方法 +buildJobName方法用于生成任务的唯一名称。该方法将任务类型描述与任务ID通过下划线连接,形成"类型_job_任务ID"的格式。 + +### buildJobGroupName方法 +buildJobGroupName方法用于生成任务组的唯一名称。该方法将任务类型描述与数据源ID通过下划线连接,形成"类型_job_group_数据源ID"的格式。 + +```mermaid +classDiagram +class ScheduleJobInfo { ++ScheduleJobType type ++CommonTaskType taskType ++Long datasourceId ++Long id ++String cronExpression ++LocalDateTime startTime ++LocalDateTime endTime +} +class QuartzExecutors { +-Scheduler scheduler +-ReadWriteLock lock ++addJob(clazz, schedule) ++deleteJob(schedule) ++deleteAllJobs(scheduler, jobGroupName) +-buildJobName(schedule) +-buildJobGroupName(schedule) +-buildDataMap(schedule) +-buildDate(localDateTime) +} +QuartzExecutors --> ScheduleJobInfo : "使用" +``` + +**图示来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L204-L215) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java#L27-L41) + +**本节来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L204-L215) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java#L27-L41) + +## 时区转换逻辑 +### buildDate方法 +buildDate方法实现了时区转换逻辑。该方法接收LocalDateTime对象,将其转换为系统默认时区的ZonedDateTime,再转换为Instant,最后生成Date对象。这种转换机制确保了在不同时区环境下任务调度的准确性。 + +```mermaid +flowchart LR +A[LocalDateTime] --> B[ZoneId.systemDefault()] +B --> C[ZonedDateTime] +C --> D[Instant] +D --> E[Date] +``` + +**图示来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L232-L237) + +**本节来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L232-L237) + +## 配置最佳实践与性能调优 +### Quartz配置最佳实践 +根据application.yaml中的配置,Quartz调度器采用JDBC存储类型,支持集群部署。关键配置包括: +- job-store-type: jdbc(使用数据库存储任务信息) +- org.quartz.jobStore.isClustered: true(启用集群模式) +- org.quartz.threadPool.threadCount: 25(线程池大小) +- org.quartz.jobStore.misfireThreshold: 60000(错失触发阈值) + +### 性能调优建议 +1. 合理设置线程池大小,避免过多线程导致系统资源耗尽 +2. 配置合适的错失触发阈值,平衡任务执行的及时性和系统负载 +3. 使用集群模式提高系统的可用性和扩展性 +4. 定期清理已完成的任务,避免数据库表过大影响性能 + +```mermaid +erDiagram +QRTZ_JOB_DETAILS { +string SCHED_NAME PK +string JOB_NAME PK +string JOB_GROUP PK +string DESCRIPTION +string JOB_CLASS_NAME +boolean IS_DURABLE +boolean IS_NONCONCURRENT +boolean IS_UPDATE_DATA +boolean REQUESTS_RECOVERY +blob JOB_DATA +} +QRTZ_TRIGGERS { +string SCHED_NAME PK +string TRIGGER_NAME PK +string TRIGGER_GROUP PK +string JOB_NAME +string JOB_GROUP +string DESCRIPTION +int64 NEXT_FIRE_TIME +int64 PREV_FIRE_TIME +int PRIORITY +string TRIGGER_STATE +string TRIGGER_TYPE +int64 START_TIME +int64 END_TIME +string CALENDAR_NAME +int MISFIRE_INSTR +blob JOB_DATA +} +QRTZ_CRON_TRIGGERS { +string SCHED_NAME PK +string TRIGGER_NAME PK +string TRIGGER_GROUP PK +string CRON_EXPRESSION +string TIME_ZONE_ID +} +QRTZ_JOB_DETAILS ||--o{ QRTZ_TRIGGERS : "包含" +QRTZ_TRIGGERS ||--o{ QRTZ_CRON_TRIGGERS : "包含" +``` + +**图示来源** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L39-L59) + +**本节来源** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L39-L59) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) + +## 结论 +QuartzExecutors类作为DataVines系统中Quartz调度器的核心管理组件,提供了完整的定时任务管理功能。通过合理的任务标识符生成策略、时区转换机制和集群配置,确保了定时任务的准确执行和系统的高可用性。在实际应用中,应根据具体需求调整配置参数,优化系统性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/\344\275\234\344\270\232\346\211\247\350\241\214\350\260\203\345\272\246\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/\344\275\234\344\270\232\346\211\247\350\241\214\350\260\203\345\272\246\345\231\250.md" new file mode 100644 index 00000000..6031a46b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/\344\275\234\344\270\232\346\211\247\350\241\214\350\260\203\345\272\246\345\231\250.md" @@ -0,0 +1,198 @@ +# 作业执行调度器 + + +**本文档引用的文件** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [OSUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/OSUtils.java) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) +- [Command.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Command.java) + + +## 目录 +1. [引言](#引言) +2. [核心工作机制](#核心工作机制) +3. [主循环资源检查](#主循环资源检查) +4. [命令获取与执行](#命令获取与执行) +5. [执行阈值控制](#执行阈值控制) +6. [重试机制与异常处理](#重试机制与异常处理) +7. [性能监控与故障排查](#性能监控与故障排查) + +## 引言 +作业执行调度器是DataVines系统中的核心组件,负责协调和管理数据质量检查作业的执行。该调度器通过一个独立的线程运行,持续监控系统资源,从外部服务获取待执行的命令,并根据系统负载和配置策略决定是否执行作业。调度器实现了完善的重试机制、异常处理和故障恢复功能,确保作业执行的可靠性和稳定性。 + +**Section sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L39-L154) + +## 核心工作机制 +作业执行调度器(JobScheduler)继承自Thread类,作为一个独立的守护线程运行。其核心工作机制围绕run方法中的无限循环展开,该循环周期性地执行以下操作:检查系统资源、获取待执行命令、验证执行阈值、提交作业执行请求。调度器通过与JobExecuteManager、JobExternalService和Register等组件的协作,实现了作业执行的全流程管理。 + +```mermaid +sequenceDiagram +participant Scheduler as JobScheduler +participant Manager as JobExecuteManager +participant Service as JobExternalService +participant Register as Register +loop 主循环 +Scheduler->>Service : listKillCommandByExecuteHost() +Service-->>Scheduler : Kill命令列表 +alt 存在Kill命令 +Scheduler->>Manager : addKillCommand() +Scheduler->>Service : deleteCommandById() +end +Scheduler->>OSUtils : checkResource() +OSUtils-->>Scheduler : 资源检查结果 +alt 资源不足 +Scheduler->>Scheduler : sleep(10*SLEEP_TIME_MILLIS) +break +end +Scheduler->>Service : getStartCommand() +Service-->>Scheduler : Start命令 +alt 存在Start命令 +Scheduler->>Service : executeCommand() +Service-->>Scheduler : JobExecution +Scheduler->>Scheduler : executionOutOfThreshold() +alt 未超出阈值 +Scheduler->>Manager : addExecuteCommand() +Scheduler->>Service : deleteCommandById() +Scheduler->>Service : updateJobExecution() +end +else +Scheduler->>Scheduler : sleep(4*SLEEP_TIME_MILLIS) +end +end +``` + +**Diagram sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L58-L134) + +**Section sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L39-L154) + +## 主循环资源检查 +调度器的主循环首先通过OSUtils工具类检查系统资源使用情况,确保在系统负载过高时不启动新的作业执行,避免对系统造成过大压力。资源检查主要关注CPU负载和内存使用情况,通过配置参数MAX_CPU_LOAD_AVG和RESERVED_MEMORY来定义资源使用上限。 + +```mermaid +flowchart TD +A[开始资源检查] --> B{Stopper.isRunning()} +B --> |否| C[退出循环] +B --> |是| D[获取CPU负载上限] +D --> E[获取保留内存大小] +E --> F[调用OSUtils.checkResource()] +F --> G{资源检查通过?} +G --> |否| H[休眠10倍SLEEP_TIME_MILLIS] +H --> B +G --> |是| I[继续执行流程] +``` + +**Diagram sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L80-L87) +- [OSUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/OSUtils.java) + +**Section sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L80-L87) + +## 命令获取与执行 +调度器通过JobExternalService与外部服务交互,获取待执行的命令。命令分为Kill命令和Start命令两种类型。对于Kill命令,调度器会将其添加到JobExecuteManager的kill命令队列中;对于Start命令,调度器会获取作业执行信息,检查执行阈值,并将作业提交到执行队列。 + +```mermaid +sequenceDiagram +participant Scheduler as JobScheduler +participant Service as JobExternalService +participant Manager as JobExecuteManager +Scheduler->>Service : getStartCommand(totalSlot, slot) +Service-->>Scheduler : Command +alt Command不为空 +Scheduler->>Service : executeCommand(command) +Service-->>Scheduler : JobExecution +Scheduler->>Scheduler : 解析引擎类型 +Scheduler->>Scheduler : executionOutOfThreshold() +alt 未超出阈值 +Scheduler->>Manager : addExecuteCommand(jobExecution) +Scheduler->>Service : deleteCommandById(command.getId()) +Scheduler->>Service : updateJobExecutionStatus() +end +else +Scheduler->>Scheduler : sleep(4*SLEEP_TIME_MILLIS) +end +``` + +**Diagram sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L89-L119) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java#L84-L106) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L542-L553) + +**Section sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L89-L119) + +## 执行阈值控制 +调度器通过executionOutOfThreshold方法实现执行阈值控制,防止特定类型的引擎作业执行数量过多,导致系统资源耗尽。该方法根据引擎类型动态获取配置的执行阈值,并计算当前已执行的作业数量,当数量达到或超过阈值时,将阻止新的作业执行。 + +```mermaid +flowchart TD +A[开始执行阈值检查] --> B{引擎类型为空?} +B --> |是| C[返回false] +B --> |否| D[构建配置键] +D --> E[获取执行阈值] +E --> F[计算当前执行数量] +F --> G{执行数量>=阈值?} +G --> |是| H[记录日志] +H --> I[返回true] +G --> |否| J[返回false] +``` + +**Diagram sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L137-L153) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L533-L540) + +**Section sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L137-L153) + +## 重试机制与异常处理 +调度器实现了基于退避算法的重试机制(RETRY_BACKOFF),在发生异常时能够自动重试,同时避免频繁重试对系统造成过大压力。重试间隔时间呈指数增长,最大间隔为10秒。异常处理机制确保在任何异常情况下都能正确更新命令状态,并记录详细的错误日志。 + +```mermaid +sequenceDiagram +participant Scheduler as JobScheduler +participant Service as JobExternalService +loop 主循环 +try +Scheduler->>Scheduler : 执行核心逻辑 +catch +Scheduler->>Scheduler : 重试次数+1 +Scheduler->>Service : updateCommand(type=ERROR) +Scheduler->>Scheduler : 记录错误日志 +Scheduler->>Scheduler : sleep(RETRY_BACKOFF[retryNum]) +finally +Scheduler->>Service : refreshCommonProperties() +end +end +``` + +**Diagram sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L122-L133) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java#L223-L229) + +**Section sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L43-L44) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L122-L133) + +## 性能监控与故障排查 +调度器的性能监控主要通过日志记录和系统资源检查实现。关键监控指标包括:调度器运行状态、资源检查结果、命令处理情况、执行阈值状态和异常信息。故障排查时应重点关注日志中的错误信息、资源使用情况和配置参数。 + +### 常见问题及解决方案 +| 问题现象 | 可能原因 | 解决方案 | +|---------|--------|--------| +| 调度器无法启动 | 依赖服务未就绪 | 检查数据库连接、注册中心状态 | +| 作业执行缓慢 | 系统资源不足 | 调整MAX_CPU_LOAD_AVG、RESERVED_MEMORY配置 | +| 作业无法提交 | 执行阈值达到上限 | 检查引擎类型执行阈值配置 | +| 频繁重试 | 外部服务不稳定 | 检查JobExternalService健康状态 | +| 内存泄漏 | 未及时清理执行上下文 | 检查JobExecuteManager的缓存清理机制 | + +**Section sources** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [OSUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/OSUtils.java) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/\350\260\203\345\272\246\344\273\273\345\212\241\345\205\203\346\225\260\346\215\256.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/\350\260\203\345\272\246\344\273\273\345\212\241\345\205\203\346\225\260\346\215\256.md" new file mode 100644 index 00000000..35ab2258 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/\350\260\203\345\272\246\344\273\273\345\212\241\345\205\203\346\225\260\346\215\256.md" @@ -0,0 +1,242 @@ +# 调度任务元数据 + + +**本文档引用的文件** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java) +- [JobSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java) +- [ScheduleJobType.java](file://datavines-server/src/main/java/io/datavines/server/enums/ScheduleJobType.java) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java) + + +## 目录 +1. [调度任务元数据概述](#调度任务元数据概述) +2. [ScheduleJobInfo类结构分析](#schedulejobinfo类结构分析) +3. [核心字段详解](#核心字段详解) +4. [执行计划定义](#执行计划定义) +5. [Quartz调度器集成](#quartz调度器集成) +6. [元数据验证与错误处理](#元数据验证与错误处理) +7. [最佳实践建议](#最佳实践建议) + +## 调度任务元数据概述 + +调度任务元数据是DataVines系统中用于定义和管理定时任务的核心数据结构。该元数据通过`ScheduleJobInfo`类实现,作为Quartz调度框架与业务逻辑之间的数据传输载体。该类封装了任务调度所需的所有必要信息,包括任务类型、数据源、执行周期等关键属性,确保调度系统能够准确地执行数据质量检查、元数据采集等周期性任务。 + +**Section sources** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L1-L57) + +## ScheduleJobInfo类结构分析 + +`ScheduleJobInfo`类是调度任务元数据的核心实现,采用Lombok注解简化代码结构,提供完整的getter和setter方法。该类定义了调度任务所需的所有属性,并通过构造函数确保对象的完整初始化。 + +```mermaid +classDiagram +class ScheduleJobInfo { ++ScheduleJobType type ++CommonTaskType taskType ++Long datasourceId ++Long id ++String cronExpression ++LocalDateTime startTime ++LocalDateTime endTime ++ScheduleJobInfo(ScheduleJobType, CommonTaskType, Long, Long, String, LocalDateTime, LocalDateTime) +} +class ScheduleJobType { ++DATA_QUALITY(0, "data_quality") ++CATALOG(1, "catalog") ++of(String) ScheduleJobType ++getCode() int ++getDescription() String +} +class CommonTaskType { ++CATALOG_METADATA_FETCH(0, "catalog_metadata_fetch", "元数据抓取") ++DATA_QUALITY_REPORT(1, "data_quality_report", "数据质量报告") ++of(Integer) CommonTaskType ++getCode() int ++getDescription() String ++getZhDescription() String +} +ScheduleJobInfo --> ScheduleJobType : "包含" +ScheduleJobInfo --> CommonTaskType : "包含" +``` + +**Diagram sources** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L25-L57) +- [ScheduleJobType.java](file://datavines-server/src/main/java/io/datavines/server/enums/ScheduleJobType.java#L24-L64) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java#L24-L74) + +**Section sources** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L25-L57) + +## 核心字段详解 + +### type字段 +`type`字段表示调度任务的类型,使用`ScheduleJobType`枚举定义。目前支持两种类型: +- **DATA_QUALITY**: 数据质量检查任务 +- **CATALOG**: 元数据采集任务 + +该字段决定了任务的处理逻辑和所属模块,在调度器中用于区分不同类型的作业。 + +### taskType字段 +`taskType`字段表示具体的任务子类型,使用`CommonTaskType`枚举定义。该字段提供了更细粒度的任务分类: +- **CATALOG_METADATA_FETCH**: 元数据抓取 +- **DATA_QUALITY_REPORT**: 数据质量报告 + +### datasourceId字段 +`datasourceId`字段存储关联的数据源ID,用于标识任务执行时需要访问的具体数据源。该ID在执行任务时被传递给数据访问组件,确保任务能够正确连接到目标数据源。 + +```mermaid +flowchart TD +A["创建调度任务"] --> B["设置datasourceId"] +B --> C["调度器执行"] +C --> D["根据datasourceId获取数据源配置"] +D --> E["执行数据质量检查"] +E --> F["生成报告"] +``` + +**Diagram sources** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L32-L33) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L170-L178) + +**Section sources** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L28-L34) +- [ScheduleJobType.java](file://datavines-server/src/main/java/io/datavines/server/enums/ScheduleJobType.java#L24-L34) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java#L24-L32) + +## 执行计划定义 + +### cronExpression字段 +`cronExpression`字段使用标准的Cron表达式语法定义任务的执行周期。系统支持完整的Cron语法,包括秒、分、时、日、月、周等时间单位的灵活配置。 + +```mermaid +sequenceDiagram +participant 用户 as "用户界面" +participant 服务 as "JobScheduleService" +participant 调度器 as "QuartzExecutors" +participant 作业 as "调度作业" +用户->>服务 : 提交cron表达式 +服务->>调度器 : 创建ScheduleJobInfo +调度器->>调度器 : 验证cron表达式 +调度器->>调度器 : 构建CronTrigger +调度器->>作业 : 注册触发器 +作业-->>调度器 : 确认注册 +调度器-->>服务 : 返回结果 +服务-->>用户 : 显示成功/失败 +``` + +**Diagram sources** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L118-L125) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L36-L37) + +### startTime和endTime字段 +`startTime`和`endTime`字段使用`LocalDateTime`类型定义任务的有效执行时间窗口。这两个字段共同确定了任务的生命周期: + +- **startTime**: 任务开始生效的时间点,调度器在此时间之后才开始执行任务 +- **endTime**: 任务结束生效的时间点,调度器在此时间之后停止执行任务 + +```mermaid +flowchart LR +A["任务创建"] --> B["设置startTime"] +B --> C["设置endTime"] +C --> D["调度器检查时间窗口"] +D --> E{"当前时间在
startTime和endTime之间?"} +E --> |是| F["执行任务"] +E --> |否| G["跳过执行"] +``` + +**Diagram sources** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L38-L40) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L90-L91) + +**Section sources** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L36-L40) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L74-L148) + +## Quartz调度器集成 + +`ScheduleJobInfo`对象作为Quartz调度器与业务逻辑之间的桥梁,通过`QuartzExecutors`类实现集成。当创建或更新调度任务时,系统会将`ScheduleJobInfo`对象转换为Quartz的`JobDetail`和`CronTrigger`。 + +```mermaid +classDiagram +class QuartzExecutors { ++addJob(Class, ScheduleJobInfo) ++deleteJob(ScheduleJobInfo) ++buildJobName(ScheduleJobInfo) ++buildJobGroupName(ScheduleJobInfo) ++buildDataMap(ScheduleJobInfo) +} +class ScheduleJobInfo { ++type ++taskType ++datasourceId ++id ++cronExpression ++startTime ++endTime +} +class JobDetail { ++JobKey ++JobDataMap +} +class CronTrigger { ++TriggerKey ++cronExpression ++startTime ++endTime +} +QuartzExecutors --> ScheduleJobInfo : "使用" +QuartzExecutors --> JobDetail : "创建" +QuartzExecutors --> CronTrigger : "创建" +JobDetail --> ScheduleJobInfo : "存储在JobDataMap" +``` + +**Diagram sources** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L74-L148) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L25-L57) + +**Section sources** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L74-L148) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L169-L178) + +## 元数据验证与错误处理 + +系统提供了完善的元数据验证机制,确保调度任务配置的正确性。主要验证包括: + +1. **Cron表达式验证**: 使用Quartz的`CronExpression.isValidExpression()`方法验证表达式语法 +2. **时间范围验证**: 确保`startTime`早于`endTime` +3. **必填字段验证**: 检查关键字段是否为空 + +```mermaid +flowchart TD +A["接收调度请求"] --> B["验证Cron表达式"] +B --> C{"表达式有效?"} +C --> |否| D["抛出SCHEDULE_CRON_IS_INVALID_ERROR"] +C --> |是| E["验证时间范围"] +E --> F{"startTime < endTime?"} +F --> |否| G["抛出时间范围错误"] +F --> |是| H["验证必填字段"] +H --> I{"所有必填字段存在?"} +I --> |否| J["抛出字段缺失错误"] +I --> |是| K["创建调度任务"] +``` + +**Diagram sources** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L239-L263) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L73-L88) + +**Section sources** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L239-L263) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L73-L88) + +## 最佳实践建议 + +1. **合理设置时间窗口**: 确保`startTime`和`endTime`设置合理,避免任务在不需要的时间段执行 +2. **Cron表达式测试**: 在生产环境部署前,使用`listFutureCronRunTimes`方法测试Cron表达式的执行时间 +3. **错误处理**: 捕获并处理`DataVinesServerException`异常,提供友好的错误提示 +4. **资源管理**: 及时清理不再需要的调度任务,避免资源浪费 +5. **监控告警**: 对关键调度任务设置监控和告警,及时发现执行异常 + +**Section sources** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L244-L263) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L180-L198) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/\350\260\203\345\272\246\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/\350\260\203\345\272\246\346\234\272\345\210\266.md" new file mode 100644 index 00000000..b42b3be5 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\236\266\346\236\204\350\256\276\350\256\241/\350\260\203\345\272\246\346\234\272\345\210\266/\350\260\203\345\272\246\346\234\272\345\210\266.md" @@ -0,0 +1,230 @@ +# 调度机制 + + +**本文档中引用的文件** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java) +- [JobSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [ScheduleJobType.java](file://datavines-server/src/main/java/io/datavines/server/enums/ScheduleJobType.java) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java) + + +## 目录 +1. [引言](#引言) +2. [调度系统架构](#调度系统架构) +3. [定时任务的创建与存储](#定时任务的创建与存储) +4. [ScheduleJobInfo 调度元数据封装](#schedulejobinfo-调度元数据封装) +5. [QuartzExecutors 调度器管理](#quartzexecutors-调度器管理) +6. [分布式任务协调与故障转移](#分布式任务协调与故障转移) +7. [调度性能优化建议](#调度性能优化建议) +8. [常见问题排查指南](#常见问题排查指南) + +## 引言 +DataVines 是一个开源的数据质量平台,其核心功能之一是基于 Quartz 的分布式调度系统。该系统负责管理数据质量检查、元数据抓取等周期性任务的执行。本文档详细描述了 DataVines 的调度机制,包括定时任务的创建、存储、触发流程,以及在分布式环境下的协调和故障转移机制。 + +## 调度系统架构 + +DataVines 的调度系统采用 Quartz 作为核心调度引擎,并通过 Spring 框架进行集成。系统架构主要包括以下几个组件: + +- **Quartz 调度器 (Scheduler)**:负责管理任务的调度和触发。 +- **JobDetail**:定义任务的具体执行逻辑。 +- **Trigger**:定义任务的触发条件,如 cron 表达式。 +- **JobStore**:用于持久化任务和触发器信息,支持 JDBC 存储,实现集群环境下的数据共享。 +- **分布式协调**:通过数据库和注册中心(如 ZooKeeper)实现多节点间的协调和故障转移。 + +```mermaid +graph TB +subgraph "前端" +UI[用户界面] +API[REST API] +end +subgraph "后端" +Scheduler[Quartz Scheduler] +JobStore[JDBC JobStore] +Registry[注册中心] +end +UI --> API +API --> Scheduler +Scheduler --> JobStore +Scheduler --> Registry +``` + +**图表来源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 定时任务的创建与存储 + +定时任务的创建流程如下: + +1. 用户通过 API 提交任务调度请求。 +2. 服务端验证请求参数,包括 cron 表达式、起止时间等。 +3. 创建 `JobSchedule` 实体并持久化到数据库。 +4. 调用 `QuartzExecutors` 将任务添加到 Quartz 调度器中。 + +任务的存储分为两部分:元数据存储在业务数据库中,而调度信息则存储在 Quartz 的 `QRTZ_*` 表中。 + +```mermaid +sequenceDiagram +participant 用户 +participant API +participant Service +participant Quartz +participant 数据库 +用户->>API : 提交调度请求 +API->>Service : 创建/更新任务 +Service->>数据库 : 保存 JobSchedule +Service->>Quartz : addJob(ScheduleJobInfo) +Quartz->>数据库 : 存储 JobDetail 和 Trigger +Quartz-->>Service : 成功 +Service-->>API : 成功 +API-->>用户 : 响应 +``` + +**图表来源** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java) +- [JobSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java) + +**节来源** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java) +- [JobSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java) + +## ScheduleJobInfo 调度元数据封装 + +`ScheduleJobInfo` 类是调度元数据的核心封装类,它包含了任务调度所需的所有信息。 + +```mermaid +classDiagram +class ScheduleJobInfo { ++ScheduleJobType type ++CommonTaskType taskType ++Long datasourceId ++Long id ++String cronExpression ++LocalDateTime startTime ++LocalDateTime endTime ++ScheduleJobInfo(type, taskType, datasourceId, id, cronExpression, startTime, endTime) +} +class ScheduleJobType { ++DATA_QUALITY(0, "data_quality") ++CATALOG(1, "catalog") +} +class CommonTaskType { ++CATALOG_METADATA_FETCH(0, "catalog_metadata_fetch") ++DATA_QUALITY_REPORT(1, "data_quality_report") +} +ScheduleJobInfo --> ScheduleJobType : "包含" +ScheduleJobInfo --> CommonTaskType : "包含" +``` + +**图表来源** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) +- [ScheduleJobType.java](file://datavines-server/src/main/java/io/datavines/server/enums/ScheduleJobType.java) +- [CommonTaskType.java](file://datavines-server/src/main/java/io/datavines/server/enums/CommonTaskType.java) + +**节来源** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) + +## QuartzExecutors 调度器管理 + +`QuartzExecutors` 类是 Quartz 调度器的管理入口,负责任务的添加、删除和更新。 + +### 任务添加流程 +1. 构建任务名称和组名。 +2. 创建 `JobDataMap`,将 `ScheduleJobInfo` 序列化后存入。 +3. 检查任务是否已存在,若存在则更新 `JobDataMap`,否则创建新任务。 +4. 创建 `CronTrigger`,设置起止时间和 misfire 策略。 +5. 将触发器与任务关联并注册到调度器。 + +### 关键代码逻辑 +- **任务名称构建**:`buildJobName` 方法根据任务类型和 ID 生成唯一任务名。 +- **数据映射**:`buildDataMap` 方法将调度信息放入 `JobDataMap`,供执行时使用。 +- **时区处理**:`buildDate` 方法处理服务器时区与调度时区的转换。 + +```mermaid +flowchart TD +Start([开始]) --> BuildName["构建任务名称和组名"] +BuildName --> BuildDataMap["构建 JobDataMap"] +BuildDataMap --> CheckExist{"任务已存在?"} +CheckExist --> |是| UpdateJob["更新 JobDataMap"] +CheckExist --> |否| CreateJob["创建新 JobDetail"] +UpdateJob --> AddJob +CreateJob --> AddJob +AddJob["添加 JobDetail 到调度器"] --> BuildTrigger["构建 CronTrigger"] +BuildTrigger --> CheckTrigger{"触发器已存在?"} +CheckTrigger --> |是| Reschedule["检查 cron 表达式并重新调度"] +CheckTrigger --> |否| Schedule["调度新触发器"] +Reschedule --> End([结束]) +Schedule --> End +``` + +**图表来源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) + +**节来源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) + +## 分布式任务协调与故障转移 + +在分布式环境下,DataVines 通过以下机制确保任务的可靠执行: + +### 集群配置 +在 `application.yaml` 中,Quartz 配置了 `isClustered: true`,启用集群模式。所有节点共享同一个数据库中的 `QRTZ_*` 表,通过数据库锁机制协调任务的获取和执行。 + +### 故障转移 +当某个节点宕机时,其他节点会通过注册中心检测到该事件,并接管其未完成的任务。 + +```mermaid +sequenceDiagram +participant 节点A +participant 节点B +participant 注册中心 +participant 数据库 +节点A->>注册中心 : 心跳注册 +节点B->>注册中心 : 心跳注册 +注册中心->>数据库 : 存储节点状态 +节点A->>数据库 : 获取任务锁 +数据库-->>节点A : 成功 +节点A->>节点A : 执行任务 +Note over 节点A,注册中心 : 节点A宕机 +注册中心->>节点B : 通知节点A离线 +节点B->>数据库 : 尝试获取任务锁 +数据库-->>节点B : 成功 +节点B->>节点B : 接管并执行任务 +``` + +**图表来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) + +## 调度性能优化建议 + +1. **合理设置线程池**:根据任务负载调整 `org.quartz.threadPool.threadCount`,避免线程过多导致资源竞争。 +2. **优化数据库性能**:确保 `QRTZ_*` 表有适当的索引,减少调度器查询延迟。 +3. **避免密集调度**:对于高频任务,考虑合并或使用更高效的触发策略。 +4. **监控 Misfire**:设置合理的 `misfireThreshold`,及时发现和处理错过触发的任务。 +5. **定期清理**:定期清理已完成或过期的任务记录,保持数据库性能。 + +## 常见问题排查指南 + +### 任务未按预期触发 +- **检查 cron 表达式**:使用 `QuartzExecutors.isValid()` 方法验证表达式是否正确。 +- **检查时区设置**:确认服务器时区与调度时区一致。 +- **查看日志**:检查 `quartz.log` 中是否有 misfire 或异常信息。 + +### 集群节点任务重复执行 +- **确认集群配置**:检查 `isClustered` 是否为 `true`。 +- **检查数据库连接**:确保所有节点连接到同一个数据库实例。 +- **查看锁机制**:确认数据库锁机制正常工作,无死锁情况。 + +### 任务执行失败 +- **检查 JobDataMap**:确认传递给任务的参数是否正确。 +- **查看执行日志**:在 `DataQualityScheduleJob.execute()` 方法中添加详细日志。 +- **验证依赖服务**:确保任务依赖的数据库、API 等服务可用。 + +**节来源** +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\344\272\244\344\272\222\346\223\215\344\275\234.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\344\272\244\344\272\222\346\223\215\344\275\234.md" new file mode 100644 index 00000000..d6c99b28 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\344\272\244\344\272\222\346\223\215\344\275\234.md" @@ -0,0 +1,112 @@ +# 交互操作 + + +**本文档引用的文件** +- [executionDashboard\index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) +- [qualityReportDashboard\index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx) +- [dashBoard.tsx](file://datavines-ui\Editor\components\Database\Detail\dashBoard.tsx) +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [request.interceptor.ts](file://datavines-ui\Editor\http\request.interceptor.ts) +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts) +- [create.ts](file://datavines-ui\Editor\http\create.ts) + + +## 目录 +1. [时间范围选择器](#时间范围选择器) +2. [指标筛选器](#指标筛选器) +3. [图表联动功能](#图表联动功能) +4. [导出功能](#导出功能) +5. [键盘快捷键](#键盘快捷键) +6. [无障碍访问支持](#无障碍访问支持) + +## 时间范围选择器 + +在数据画像界面中,用户可以通过时间范围选择器来筛选特定时间段内的数据。该选择器位于执行仪表板和质量报告仪表板的查询条件区域,允许用户选择开始时间和结束时间。 + +用户可以通过点击日期选择框,从弹出的日期时间选择器中选择具体的日期和时间。选择器支持精确到秒的时间选择,用户可以自由选择任意时间段的数据进行分析。选择完成后,点击"查询"按钮即可更新所有相关图表和数据表格。 + +**Section sources** +- [executionDashboard\index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx#L512-L513) +- [qualityReportDashboard\index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx#L461) + +## 指标筛选器 + +指标筛选器允许用户根据不同的数据质量指标来过滤和查看数据。在执行仪表板中,用户可以通过下拉选择框选择特定的指标类型,系统会根据选择的指标类型更新所有相关图表和数据。 + +指标筛选器支持多选和条件过滤功能。用户可以选择一个或多个指标类型,系统会同时显示这些指标的数据。筛选器的选项是动态加载的,根据系统中配置的数据质量指标自动生成。 + +当用户选择或取消选择某个指标时,系统会自动发送请求到后端服务,获取相应的数据并更新界面。这种实时的筛选功能使用户能够快速探索不同指标下的数据质量情况。 + +**Section sources** +- [executionDashboard\index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx#L506-L511) + +## 图表联动功能 + +数据画像界面实现了强大的图表联动功能。当用户在一个图表中选择特定的数据区域时,其他相关的图表会自动同步更新,显示与所选区域相关的数据。 + +这种联动功能基于ECharts图表库实现。在`dashBoard.tsx`组件中,每个图表都有一个唯一的ID,并且通过React的useEffect钩子监听数据变化。当某个图表的数据发生变化时,它会触发重新渲染,同时通过状态管理机制通知其他相关图表更新。 + +例如,在执行仪表板中,当用户选择特定的数据库、表或列时,饼图、趋势图和数据表格都会同步更新,显示与所选实体相关的数据质量信息。这种联动效果为用户提供了无缝的数据探索体验。 + +```mermaid +flowchart TD +A[用户选择数据区域] --> B{图表组件检测到选择} +B --> C[更新组件状态] +C --> D[通过useEffect触发重新渲染] +D --> E[发送API请求获取新数据] +E --> F[更新其他相关图表] +F --> G[界面同步显示新数据] +``` + +**Diagram sources** +- [dashBoard.tsx](file://datavines-ui\Editor\components\Database\Detail\dashBoard.tsx#L36-L62) +- [executionDashboard\index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) + +## 导出功能 + +系统提供了多种数据导出选项,包括图片和数据文件的导出。在图表的工具栏中,用户可以找到"保存为图片"的功能,点击后可以将当前图表导出为PNG格式的图片文件。 + +对于数据表格,系统支持导出为多种格式的数据文件。虽然在当前代码中没有直接看到导出功能的实现,但通过HTTP请求配置可以看出系统具备文件导出的能力。在`response.interceptor.ts`中,系统能够处理Blob类型的响应数据,这通常是文件下载的实现方式。 + +导出功能的实现基于axios HTTP客户端,通过设置适当的请求头和响应类型,系统可以从后端服务获取导出的数据并触发浏览器的下载行为。 + +```mermaid +sequenceDiagram +participant 用户 +participant 前端界面 +participant HTTP客户端 +participant 后端服务 +用户->>前端界面 : 点击导出按钮 +前端界面->>HTTP客户端 : 发送导出请求 +HTTP客户端->>后端服务 : 带有特定头信息的GET请求 +后端服务-->>HTTP客户端 : 返回Blob格式的文件数据 +HTTP客户端-->>前端界面 : 处理响应数据 +前端界面-->>用户 : 触发浏览器下载 +``` + +**Diagram sources** +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts#L7-L11) +- [create.ts](file://datavines-ui\Editor\http\create.ts) + +## 键盘快捷键 + +系统支持多种键盘快捷键操作,提高用户的操作效率。虽然在代码中没有明确列出所有快捷键,但通过搜索表单组件的实现可以看出系统支持回车键触发搜索功能。 + +在`SearchForm\index.tsx`组件中,`onPressEnter`事件监听器被绑定到搜索输入框,当用户在输入框中按下回车键时,会自动触发搜索操作。这种设计避免了用户必须用鼠标点击搜索按钮的繁琐操作。 + +此外,系统可能还支持其他常见的快捷键操作,如Tab键在表单字段间切换,Esc键关闭弹出窗口等,这些是基于Ant Design组件库的默认行为。 + +**Section sources** +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx#L31-L33) + +## 无障碍访问支持 + +系统在设计时考虑了无障碍访问的需求,确保所有用户都能方便地使用各项功能。通过使用语义化的HTML元素和ARIA属性,系统为屏幕阅读器等辅助技术提供了良好的支持。 + +在图表组件中,系统使用了适当的标题和描述信息,帮助视障用户理解图表的内容。在表单和控件中,每个输入元素都有对应的标签,确保键盘导航的流畅性。 + +HTTP请求拦截器和响应拦截器的设计也考虑了错误处理的可访问性,当请求失败时,系统会返回清晰的错误信息,帮助用户理解问题所在并采取相应措施。 + +**Section sources** +- [request.interceptor.ts](file://datavines-ui\Editor\http\request.interceptor.ts) +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\345\210\206\346\236\220\345\234\272\346\231\257.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\345\210\206\346\236\220\345\234\272\346\231\257.md" new file mode 100644 index 00000000..6c33ede9 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\345\210\206\346\236\220\345\234\272\346\231\257.md" @@ -0,0 +1,179 @@ +# 分析场景 + + +**本文档引用的文件** +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java) +- [JobQualityReportServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobQualityReportServiceImpl.java) +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java) +- [JobQualityReportScoreTrend.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobQualityReportScoreTrend.java) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [FlinkDataProfileMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-config/src/main/java/io/datavines/engine/flink/config/FlinkDataProfileMetricBuilder.java) +- [SinkSqlBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/SinkSqlBuilder.java) +- [LocalDataProfileMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalDataProfileMetricBuilder.java) +- [README.md](file://README.md) +- [README.zh-CN.md](file://README.zh-CN.md) + + +## 目录 +1. [引言](#引言) +2. [时间维度分析数据质量趋势](#时间维度分析数据质量趋势) +3. [多环境对比分析](#多环境对比分析) +4. [异常检测机制](#异常检测机制) +5. [数据治理场景](#数据治理场景) +6. [可视化分析案例](#可视化分析案例) +7. [结论](#结论) + +## 引言 +DataVines 是一个易于使用的数据质量服务平台,支持多种数据质量度量和分析场景。该平台通过插件化设计,支持多种数据源、检查规则、执行引擎和告警通道。本文档重点描述 DataVines 在实际业务中的分析场景,包括时间维度分析、多环境对比、异常检测、数据治理和可视化分析。 + +**Section sources** +- [README.md](file://README.md#L24-L76) +- [README.zh-CN.md](file://README.zh-CN.md#L47-L85) + +## 时间维度分析数据质量趋势 +DataVines 支持基于时间维度的数据质量趋势分析。系统通过定时执行数据探测任务,生成数据质量报告,并记录历史数据质量评分。`JobQualityReport` 表用于存储数据质量报告,包含数据源ID、实体级别、数据库名称、表名称、列名称、质量评分和报告日期等字段。 + +系统提供 `JobQualityReportScoreTrend` 类,用于表示数据质量评分趋势,包含日期列表和评分列表。通过分析历史评分数据,用户可以监控数据质量的变化趋势,识别潜在的数据质量问题。 + +```mermaid +flowchart TD +A[开始] --> B[执行数据探测任务] +B --> C[生成数据质量报告] +C --> D[存储报告到JobQualityReport表] +D --> E[计算质量评分] +E --> F[更新评分趋势] +F --> G[结束] +``` + +**Diagram sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L610-L626) +- [JobQualityReportScoreTrend.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobQualityReportScoreTrend.java#L1-L30) + +**Section sources** +- [JobQualityReportScoreTrend.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobQualityReportScoreTrend.java#L1-L30) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L610-L626) + +## 多环境对比分析 +DataVines 支持开发、测试、生产环境间的数据特征比较。通过配置不同的数据源连接信息,用户可以在不同环境中执行相同的数据质量检查任务,并比较结果。 + +系统支持多种数据源,包括 MySQL、Impala、StarRocks、Doris、Presto、Trino、ClickHouse 和 PostgreSQL。用户可以为每个环境配置相应的数据源,并使用相同的检查规则进行数据质量评估。 + +```mermaid +graph TB +subgraph 开发环境 +DevDB[(开发数据库)] +end +subgraph 测试环境 +TestDB[(测试数据库)] +end +subgraph 生产环境 +ProdDB[(生产数据库)] +end +DevDB --> |执行检查任务| DataVines +TestDB --> |执行检查任务| DataVines +ProdDB --> |执行检查任务| DataVines +DataVines --> |比较结果| Report[对比报告] +``` + +**Diagram sources** +- [README.md](file://README.md#L71-L73) +- [README.zh-CN.md](file://README.zh-CN.md#L73-L74) + +**Section sources** +- [README.md](file://README.md#L71-L73) +- [README.zh-CN.md](file://README.zh-CN.md#L73-L74) + +## 异常检测机制 +DataVines 基于历史数据自动识别异常值。系统通过分析历史数据质量评分,建立正常范围模型。当新的数据质量评分超出正常范围时,系统会标记为异常。 + +`DataQualityLevel` 枚举定义了数据质量等级,包括不合格、合格、中等、良好和优秀。系统根据评分范围自动确定数据质量等级。当数据质量等级显著下降时,系统会触发异常检测。 + +```mermaid +stateDiagram-v2 +[*] --> 正常 +正常 --> 异常 : 评分低于阈值 +异常 --> 正常 : 评分恢复到正常范围 +异常 --> 告警 : 持续异常 +告警 --> 正常 : 问题解决 +``` + +**Diagram sources** +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java#L26-L30) + +**Section sources** +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java#L57-L73) + +## 数据治理场景 +### 数据标准符合性检查 +DataVines 支持数据标准符合性检查,确保数据符合预定义的标准。系统提供多种检查规则类型,包括单表单列检查、单表自定义SQL检查、跨表准确性检查和两表值比对检查。 + +`MetricType` 枚举定义了四种检查规则类型:单表检查、单表自定义SQL检查、跨表准确性检查和两表值比对检查。用户可以根据需要选择合适的检查类型。 + +### 数据资产价值评估 +DataVines 通过数据质量评分评估数据资产价值。高质量的数据资产具有更高的价值。系统根据数据质量等级(不合格、合格、中等、良好、优秀)对数据资产进行分类和评估。 + +```mermaid +erDiagram +DATA_QUALITY_LEVEL { +int code PK +string description +string zh_description +} +JOB_QUALITY_REPORT { +bigint id PK +bigint datasource_id FK +varchar entity_level +varchar database_name +varchar table_name +varchar column_name +decimal score +date report_date +} +DATA_QUALITY_LEVEL ||--o{ JOB_QUALITY_REPORT : "has" +``` + +**Diagram sources** +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java#L26-L30) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L610-L626) + +**Section sources** +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java#L1-L74) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java#L24-L34) + +## 可视化分析案例 +### 数据漂移检测 +DataVines 通过数据分布视图检测数据漂移。系统支持自动识别列类型,并匹配合适的数据概况指标。当数据分布发生显著变化时,系统会标记为数据漂移。 + +`MetricDimension` 枚举定义了数据质量维度,包括完整性、一致性、有效性、时效性、唯一性和准确性。系统根据这些维度分析数据特征,识别数据漂移。 + +### 数据衰减分析 +DataVines 监控表行数趋势,检测数据衰减。系统通过定时执行数据探测任务,记录表行数变化。当表行数持续减少时,系统会标记为数据衰减。 + +```mermaid +flowchart LR +A[数据探测任务] --> B[提取数据特征] +B --> C[完整性分析] +C --> D[一致性分析] +D --> E[有效性分析] +E --> F[时效性分析] +F --> G[唯一性分析] +G --> H[准确性分析] +H --> I[生成数据画像] +I --> J[识别数据漂移] +J --> K[检测数据衰减] +``` + +**Diagram sources** +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java#L24-L38) +- [FlinkDataProfileMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-config/src/main/java/io/datavines/engine/flink/config/FlinkDataProfileMetricBuilder.java#L31-L57) +- [SinkSqlBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/SinkSqlBuilder.java#L70-L90) + +**Section sources** +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java#L24-L38) +- [FlinkDataProfileMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-config/src/main/java/io/datavines/engine/flink/config/FlinkDataProfileMetricBuilder.java#L31-L57) +- [SinkSqlBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/SinkSqlBuilder.java#L70-L90) + +## 结论 +DataVines 提供了全面的数据分析能力,支持时间维度分析、多环境对比、异常检测、数据治理和可视化分析。通过这些功能,用户可以有效监控数据质量,识别潜在问题,确保数据资产的可靠性和价值。平台的插件化设计使其具有良好的扩展性,能够适应不同的业务需求和技术环境。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272.md" new file mode 100644 index 00000000..a984f0e1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272.md" @@ -0,0 +1,197 @@ +# 可视化展示 + + +**本文档引用的文件** +- [index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\index.tsx) +- [executionDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) +- [qualityReportDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx) +- [dashBoard.tsx](file://datavines-ui\Editor\components\Database\Detail\dashBoard.tsx) +- [profileContent.tsx](file://datavines-ui\Editor\components\Database\profileContent.tsx) +- [package.json](file://datavines-ui\package.json) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CatalogEntityInstanceServiceImpl.java) +- [DataTime2ValueItem.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\vo\DataTime2ValueItem.java) + + +## 目录 +1. [数据画像可视化概览](#数据画像可视化概览) +2. [核心可视化组件](#核心可视化组件) +3. [时间维度趋势分析](#时间维度趋势分析) +4. [多维度数据对比分析](#多维度数据对比分析) +5. [可视化配置选项](#可视化配置选项) +6. [用户体验最佳实践](#用户体验最佳实践) +7. [前端技术实现](#前端技术实现) + +## 数据画像可视化概览 + +数据画像可视化展示模块是数据质量平台的核心功能之一,通过丰富的图表组件直观呈现数据特征和质量状况。系统提供了执行仪表板和质量报告仪表板两大核心视图,分别从任务执行情况和数据质量评分两个维度进行展示。执行仪表板主要展示数据质量检查任务的执行统计、趋势分析和失败任务详情,而质量报告仪表板则聚焦于数据质量评分、趋势变化和详细报告。这些可视化组件基于ECharts图表库构建,结合Ant Design UI框架,实现了响应式布局和交互式体验。 + +**Section sources** +- [index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\index.tsx) + +## 核心可视化组件 + +### 趋势图 +趋势图采用折线图形式展示数据质量指标随时间的变化趋势。在执行仪表板中,趋势图展示了所有、成功和失败任务数量的时间序列变化,帮助用户快速识别执行异常。在质量报告仪表板中,趋势图则展示了数据质量评分的历史变化,便于评估数据质量的改进情况。图表配置了平滑曲线、标记点和平均线等视觉元素,增强了数据趋势的可读性。 + +```mermaid +flowchart TD +A[获取时间范围参数] --> B[调用后端API获取趋势数据] +B --> C[构建ECharts折线图配置] +C --> D[渲染趋势图] +D --> E[用户交互: 缩放, 提示] +``` + +**Diagram sources** +- [executionDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) +- [qualityReportDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx) + +### 分布图 +分布图以柱状图形式展示数据值的分布情况,主要用于数据画像中的Top 10值分布分析。该图表通过调用`/catalog/profile/column/{uuid}`接口获取特定列的值分布数据,将出现频率最高的10个值及其占比可视化展示。柱状图配置了最大宽度限制和数据标签,确保在值较多时仍能清晰展示。 + +```mermaid +flowchart TD +A[获取列UUID] --> B[调用列画像API] +B --> C[解析Top 10分布数据] +C --> D[构建ECharts柱状图配置] +D --> E[渲染分布图] +``` + +**Diagram sources** +- [profileContent.tsx](file://datavines-ui\Editor\components\Database\profileContent.tsx) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CatalogEntityInstanceServiceImpl.java) + +### 热力图 +热力图在本系统中以仪表盘(Gauge Chart)形式实现,用于直观展示数据质量评分。仪表盘采用半圆形设计,将评分范围划分为多个颜色区域,从红色(低分)到绿色(高分)渐变,使用户能够一目了然地判断数据质量水平。仪表盘还显示了具体的评分值和质量等级,提供了详细的评估信息。 + +```mermaid +flowchart TD +A[获取数据源和表信息] --> B[调用质量评分API] +B --> C[构建ECharts仪表盘配置] +C --> D[渲染热力图] +``` + +**Diagram sources** +- [qualityReportDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx) + +## 时间维度趋势分析 + +系统支持通过时间维度查看数据特征的变化趋势,用户可以通过日期选择器设置自定义的时间范围。在执行仪表板中,用户可以设置开始时间和结束时间来查询特定时间段内的任务执行情况。系统通过`/job/execution/trend-bar`接口获取趋势数据,该接口返回日期列表、总任务数、成功任务数和失败任务数等信息,用于构建趋势图。 + +时间维度分析不仅限于任务执行情况,还包括数据质量评分的趋势分析。用户可以通过报告时间选择器查看历史质量评分的变化趋势,系统通过`/job/quality-report/score-trend`接口获取评分趋势数据,帮助用户评估数据质量的长期变化。 + +**Section sources** +- [executionDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) +- [qualityReportDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx) +- [DataTime2ValueItem.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\vo\DataTime2ValueItem.java) + +## 多维度数据对比分析 + +系统支持多维度数据对比分析功能,用户可以通过级联选择器选择不同的数据源、数据库、表和列进行对比分析。在执行仪表板中,用户可以选择特定的实体(数据库、表或列)和指标类型进行过滤,系统会返回相应的执行统计数据。这种多维度过滤机制使用户能够深入分析特定数据对象的质量状况。 + +此外,系统还支持不同环境间的数据特征比较,虽然当前代码中未直接体现,但通过选择不同的数据源ID,用户可以间接实现跨环境的数据对比。未来可以通过增强数据源管理功能,提供更直观的环境对比视图。 + +**Section sources** +- [executionDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) +- [qualityReportDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx) + +## 可视化配置选项 + +系统提供了丰富的可视化配置选项,用户可以根据需要自定义展示内容。主要配置选项包括: + +- **图表类型选择**: 系统根据数据类型自动选择合适的图表类型,如趋势数据使用折线图,分布数据使用柱状图,评分数据使用仪表盘。 +- **时间范围设置**: 用户可以通过日期选择器设置查询的时间范围,支持精确到秒的时间选择。 +- **指标筛选**: 用户可以通过下拉选择器筛选特定的指标类型,如完整性、一致性、有效性等。 +- **实体选择**: 通过级联选择器,用户可以选择特定的数据库、表和列进行分析。 + +这些配置选项通过React组件的状态管理实现,用户操作会触发状态更新,进而重新获取数据并刷新图表。 + +**Section sources** +- [executionDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) +- [qualityReportDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx) + +## 用户体验最佳实践 + +为了提供最佳的用户体验,系统实现了多项优化措施: + +- **空状态处理**: 当图表数据为空时,系统会显示友好的空状态提示,避免用户面对空白图表感到困惑。 +- **数据提示**: 所有图表都配置了工具提示(Tooltip),当用户悬停在数据点上时,会显示详细的数据信息。 +- **响应式布局**: 图表组件采用响应式设计,能够适应不同屏幕尺寸,确保在移动设备上也能正常显示。 +- **加载状态**: 在数据加载过程中,系统会显示加载动画,提升用户体验。 +- **异常识别**: 通过颜色编码(如红色表示失败任务),用户可以快速识别数据异常。 + +这些最佳实践确保了用户能够高效、直观地理解和分析数据质量状况。 + +**Section sources** +- [dashBoard.tsx](file://datavines-ui\Editor\components\Database\Detail\dashBoard.tsx) +- [executionDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) + +## 前端技术实现 + +### React组件结构 +可视化展示功能基于React函数组件实现,采用Hooks进行状态管理和副作用处理。核心组件包括: +- `Dashboard`: 主容器组件,包含选项卡用于切换执行仪表板和质量报告仪表板。 +- `ExecutionDashboard`: 执行仪表板组件,包含趋势图、饼图和任务列表。 +- `QualityReportDashboard`: 质量报告仪表板组件,包含评分仪表盘、趋势图和报告列表。 +- `DashBoard`: 通用图表组件,封装了ECharts的初始化和渲染逻辑。 + +### 数据绑定机制 +系统采用Axios进行HTTP请求,通过自定义Hook `useRequest`封装API调用。数据绑定流程如下: +1. 组件初始化时调用API获取数据 +2. 将API返回的数据转换为ECharts配置对象 +3. 通过React状态管理更新图表配置 +4. ECharts组件监听配置变化并重新渲染 + +系统依赖ECharts 5.4.0作为图表库,Ant Design 5.0.5作为UI框架,确保了高性能和现代化的用户界面。 + +```mermaid +classDiagram +class Dashboard { ++activeKey : string ++render() +} +class ExecutionDashboard { +-dqBarOption : any +-dqPieOption : any +-entityParam : any +-pageParam : any ++getJobExecutionData() ++getJobExecutionAggPie() ++getJobExecutionTrendBar() ++render() +} +class QualityReportDashboard { +-dqBarOption : any +-dqGaugeOption : any +-entityParam : any +-pageParam : any ++getJobExecutionData() ++getJobExecutionAggPie() ++getJobExecutionTrendBar() ++render() +} +class DashBoard { +-myChart : any +-option : any ++initECharts() ++setOption() ++render() +} +Dashboard --> ExecutionDashboard : 包含 +Dashboard --> QualityReportDashboard : 包含 +ExecutionDashboard --> DashBoard : 使用 +QualityReportDashboard --> DashBoard : 使用 +``` + +**Diagram sources** +- [index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\index.tsx) +- [executionDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) +- [qualityReportDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx) +- [dashBoard.tsx](file://datavines-ui\Editor\components\Database\Detail\dashBoard.tsx) +- [package.json](file://datavines-ui\package.json) + +**Section sources** +- [index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\index.tsx) +- [executionDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\executionDashboard\index.tsx) +- [qualityReportDashboard/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Dashboard\qualityReportDashboard\index.tsx) +- [dashBoard.tsx](file://datavines-ui\Editor\components\Database\Detail\dashBoard.tsx) +- [package.json](file://datavines-ui\package.json) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\345\233\276\350\241\250\347\261\273\345\236\213.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\345\233\276\350\241\250\347\261\273\345\236\213.md" new file mode 100644 index 00000000..a4ef883f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\345\217\257\350\247\206\345\214\226\345\261\225\347\244\272/\345\233\276\350\241\250\347\261\273\345\236\213.md" @@ -0,0 +1,217 @@ +# 图表类型 + + +**本文档中引用的文件** +- [executionDashboard/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Dashboard/executionDashboard/index.tsx) +- [dashBoard.tsx](file://datavines-ui/Editor/components/Database/Detail/dashBoard.tsx) +- [ColumnHistogram.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-histogram/src/main/java/io/datavines/metric/plugin/ColumnHistogram.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionDashboardParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionDashboardParam.java) + + +## 目录 +1. [引言](#引言) +2. [趋势图](#趋势图) +3. [分布图](#分布图) +4. [热力图](#热力图) +5. [柱状图](#柱状图) +6. [图表数据映射逻辑](#图表数据映射逻辑) +7. [配置参数说明](#配置参数说明) +8. [最佳实践建议](#最佳实践建议) +9. [前端组件实现](#前端组件实现) + +## 引言 +数据画像是大数据质量监控平台中的核心功能,通过可视化图表展示数据质量指标的变化趋势和分布情况。本文档详细描述了平台中使用的各种图表类型,包括趋势图、分布图、热力图和柱状图,以及它们在数据特征分析中的应用场景。 + +## 趋势图 +趋势图用于展示数据行数随时间的变化情况,帮助用户识别数据质量指标的趋势和周期性模式。在平台中,趋势图通过`/job/execution/trend-bar` API端点获取数据,展示作业执行的成功、失败和总数趋势。 + +**图表应用场景**: +- 监控数据质量指标随时间的变化 +- 识别数据质量问题的周期性模式 +- 跟踪数据质量改进措施的效果 + +```mermaid +graph TD +A[前端组件] --> B[调用趋势图API] +B --> C[后端服务处理] +C --> D[数据库查询] +D --> E[返回趋势数据] +E --> F[前端渲染图表] +``` + +**图表来源** +- [executionDashboard/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Dashboard/executionDashboard/index.tsx#L259-L318) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L118-L122) + +## 分布图 +分布图用于显示数值型数据的分布情况,帮助用户理解数据的集中趋势和离散程度。平台中的分布图主要通过柱状图和直方图实现,展示数据在不同区间内的分布频率。 + +**图表应用场景**: +- 分析数值型数据的分布特征 +- 识别数据异常值和离群点 +- 评估数据的正态性 + +```mermaid +classDiagram +class ColumnHistogram { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map config) ++ExecuteSql getActualValue(Map inputParameter) ++String getActualValueType() ++List suitableType() +} +ColumnHistogram --> MetricDimension : "使用" +ColumnHistogram --> MetricType : "使用" +ColumnHistogram --> DataVinesDataType : "使用" +``` + +**图表来源** +- [ColumnHistogram.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-histogram/src/main/java/io/datavines/metric/plugin/ColumnHistogram.java) +- [dashBoard.tsx](file://datavines-ui/Editor/components/Database/Detail/dashBoard.tsx#L1-L83) + +## 热力图 +热力图用于展示多维数据的密度和强度分布,通过颜色深浅表示数值大小。在数据画像中,热力图可以用于展示不同数据源、表或列之间的质量关联性。 + +**图表应用场景**: +- 展示多维数据的关联性 +- 识别数据质量问题的热点区域 +- 可视化数据质量评分矩阵 + +**图表来源** +- [dashBoard.tsx](file://datavines-ui/Editor/components/Database/Detail/dashBoard.tsx#L2-L35) +- [executionDashboard/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Dashboard/executionDashboard/index.tsx#L213-L249) + +## 柱状图 +柱状图用于比较不同类别或时间段的数据值,通过柱子的高度表示数值大小。在平台中,柱状图主要用于展示作业执行的聚合统计信息。 + +**图表应用场景**: +- 比较不同数据源的质量指标 +- 展示作业执行状态的分布 +- 对比不同时间段的数据质量 + +```mermaid +sequenceDiagram +participant 前端 as 前端组件 +participant API as API服务 +participant 服务 as 后端服务 +participant 数据库 as 数据库 +前端->>API : POST /job/execution/agg-pie +API->>服务 : 调用getJobExecutionAggPie +服务->>数据库 : 查询执行统计 +数据库-->>服务 : 返回统计结果 +服务-->>API : 返回聚合数据 +API-->>前端 : 返回饼图数据 +前端->>前端 : 渲染图表 +``` + +**图表来源** +- [executionDashboard/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Dashboard/executionDashboard/index.tsx#L198-L255) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L112-L116) + +## 图表数据映射逻辑 +图表的数据映射逻辑定义了如何将原始数据转换为可视化元素。平台使用ECharts作为可视化库,通过配置option对象来定义图表的外观和行为。 + +**数据映射流程**: +1. 前端组件调用API获取原始数据 +2. 将API返回的数据转换为ECharts所需的格式 +3. 配置图表的option对象 +4. 使用ECharts初始化并渲染图表 + +```mermaid +flowchart TD +A[原始数据] --> B[数据预处理] +B --> C[格式转换] +C --> D[配置图表选项] +D --> E[图表渲染] +E --> F[用户交互] +``` + +**图表来源** +- [dashBoard.tsx](file://datavines-ui/Editor/components/Database/Detail/dashBoard.tsx#L36-L62) +- [executionDashboard/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Dashboard/executionDashboard/index.tsx#L273-L317) + +## 配置参数说明 +图表的配置参数定义了图表的外观和行为特性。主要配置参数包括: + +**通用配置参数**: +- `tooltip`: 工具提示配置 +- `legend`: 图例配置 +- `grid`: 网格布局配置 +- `xAxis`: X轴配置 +- `yAxis`: Y轴配置 +- `series`: 数据系列配置 + +**特定图表配置**: +- 趋势图:`boundaryGap`, `smooth` +- 分布图:`radius`, `avoidLabelOverlap` +- 热力图:`color`, `min`, `max` +- 柱状图:`barWidth`, `barGap` + +**图表来源** +- [executionDashboard/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Dashboard/executionDashboard/index.tsx#L273-L317) +- [dashBoard.tsx](file://datavines-ui/Editor/components/Database/Detail/dashBoard.tsx#L20-L35) + +## 最佳实践建议 +为了有效使用图表进行数据特征分析,建议遵循以下最佳实践: + +**图表选择原则**: +- 时间序列数据使用趋势图 +- 分布特征分析使用分布图 +- 多维关联分析使用热力图 +- 类别比较使用柱状图 + +**可视化设计建议**: +- 保持图表简洁,避免信息过载 +- 使用一致的颜色方案 +- 提供交互功能,如缩放和筛选 +- 添加适当的标签和说明 + +**性能优化建议**: +- 对大数据集进行采样 +- 使用增量更新 +- 优化数据查询 + +**图表来源** +- [dashBoard.tsx](file://datavines-ui/Editor/components/Database/Detail/dashBoard.tsx) +- [executionDashboard/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Dashboard/executionDashboard/index.tsx) + +## 前端组件实现 +前端组件负责接收后端数据并渲染图表。平台使用React和ECharts实现图表组件,通过HTTP请求获取数据。 + +**组件实现要点**: +- 使用useEffect监听数据变化 +- 调用ECharts API初始化图表 +- 处理数据加载状态 +- 实现图表更新逻辑 + +```mermaid +classDiagram +class DashBoard { ++String id ++Object option ++Object style ++useState myChart ++useEffect renderChart() +} +class ExecutionDashboard { ++Object entityParam ++Object pageParam ++Object metricType ++useState dqBarOption ++useState dqPieOption ++useState tableData ++useEffect refreshData() ++getJobExecutionData() ++getJobExecutionAggPie() ++getJobExecutionTrendBar() +} +DashBoard --> ExecutionDashboard : "被使用" +``` + +**图表来源** +- [dashBoard.tsx](file://datavines-ui/Editor/components/Database/Detail/dashBoard.tsx) +- [executionDashboard/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Dashboard/executionDashboard/index.tsx) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\346\225\260\346\215\256\347\224\273\345\203\217.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\346\225\260\346\215\256\347\224\273\345\203\217.md" new file mode 100644 index 00000000..282084ee --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\346\225\260\346\215\256\347\224\273\345\203\217.md" @@ -0,0 +1,421 @@ +# 数据画像 + + +**本文档引用的文件** +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java) +- [DataVinesDataType.java](file://datavines-common/src/main/java/io/datavines/common/enums/DataVinesDataType.java) +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java) +- [CatalogEntityProfile.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityProfile.java) +- [CatalogProfileScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/catalog/profile/CatalogProfileScheduleCreateOrUpdate.java) +- [RunProfileRequest.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/catalog/profile/RunProfileRequest.java) +- [profileContent.tsx](file://datavines-ui/Editor/components/Database/profileContent.tsx) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [README.md](file://README.md) + + +## 目录 +1. [简介](#简介) +2. [数据画像采集内容](#数据画像采集内容) +3. [画像数据存储结构](#画像数据存储结构) +4. [画像任务配置与触发](#画像任务配置与触发) +5. [画像结果展示](#画像结果展示) +6. [使用场景](#使用场景) +7. [执行引擎支持](#执行引擎支持) +8. [使用示例](#使用示例) +9. [常见问题](#常见问题) + +## 简介 + +DataVines的数据画像功能提供全面的数据特征分析能力,能够自动识别数据表的结构特征并生成详细的画像报告。该功能支持定时执行数据检测,输出数据画像报告,并支持自动识别列类型以匹配适当的数据画像指标。通过数据画像,用户可以深入了解数据的分布特征、质量状况和变化趋势,为数据探索、质量基线建立和异常检测提供支持。 + +**Section sources** +- [README.md](file://README.md#L58-L65) + +## 数据画像采集内容 + +DataVines的数据画像功能采集多种数据特征指标,根据数据类型的不同,采集的指标也有所差异。系统通过`DataVinesDataType`枚举类定义了不同类型数据的画像指标集合。 + +### 字符串类型数据画像指标 + +对于字符串类型的数据,系统采集以下指标: +- **空值统计**:包括空值数量(`column_null`)和非空值数量(`column_not_null`) +- **唯一值统计**:包括唯一值数量(`column_unique`)和不同值数量(`column_distinct`) +- **长度统计**:包括平均长度(`column_avg_length`)、最大长度(`column_max_length`)和最小长度(`column_min_length`) +- **空白值统计**:空白值数量(`column_blank`) +- **极值统计**:最大值(`column_max`)和最小值(`column_min`) +- **分布统计**:数据分布直方图(`column_histogram`) + +### 数值类型数据画像指标 + +对于数值类型的数据,系统采集以下指标: +- **空值统计**:包括空值数量(`column_null`)和非空值数量(`column_not_null`) +- **唯一值统计**:包括唯一值数量(`column_unique`)和不同值数量(`column_distinct`) +- **极值统计**:最大值(`column_max`)和最小值(`column_min`) +- **统计指标**:平均值(`column_avg`)、总和(`column_sum`)、标准差(`column_std_dev`)和方差(`column_variance`) +- **分布统计**:数据分布直方图(`column_histogram`) + +### 日期时间类型数据画像指标 + +对于日期时间类型的数据,系统采集以下指标: +- **空值统计**:包括空值数量(`column_null`)和非空值数量(`column_not_null`) +- **唯一值统计**:包括唯一值数量(`column_unique`)和不同值数量(`column_distinct`) +- **极值统计**:最大值(`column_max`)和最小值(`column_min`) +- **分布统计**:数据分布直方图(`column_histogram`) + +此外,系统还支持表级别的行数统计(`table_row_count`),用于监控表数据量的变化趋势。 + +```mermaid +graph TD +A[数据类型] --> B[字符串类型] +A --> C[数值类型] +A --> D[日期时间类型] +B --> B1[空值统计] +B --> B2[唯一值统计] +B --> B3[长度统计] +B --> B4[空白值统计] +B --> B5[极值统计] +B --> B6[分布统计] +C --> C1[空值统计] +C --> C2[唯一值统计] +C --> C3[极值统计] +C --> C4[统计指标] +C --> C5[分布统计] +D --> D1[空值统计] +D --> D2[唯一值统计] +D --> D3[极值统计] +D --> D4[分布统计] +E[表级别] --> E1[行数统计] +``` + +**Diagram sources** +- [DataVinesDataType.java](file://datavines-common/src/main/java/io/datavines/common/enums/DataVinesDataType.java#L30-L110) + +**Section sources** +- [DataVinesDataType.java](file://datavines-common/src/main/java/io/datavines/common/enums/DataVinesDataType.java#L30-L110) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L456-L733) + +## 画像数据存储结构 + +DataVines使用专门的数据库表来存储数据画像结果,确保画像数据的持久化和可追溯性。系统通过`CatalogEntityProfile`实体类定义了画像数据的存储结构。 + +### 数据库表结构 + +画像数据存储在`dv_catalog_entity_profile`表中,该表的主要字段包括: + +| 字段名 | 数据类型 | 描述 | +|-------|--------|------| +| id | BIGINT | 主键,自增 | +| entity_uuid | VARCHAR | 实体UUID,关联到数据目录中的表或列 | +| metric_name | VARCHAR | 指标名称,如"column_null"、"column_unique"等 | +| actual_value | VARCHAR | 实际值,存储指标的计算结果 | +| actual_value_type | VARCHAR | 实际值类型,如"count"、"percentage"等 | +| data_date | VARCHAR | 数据日期,用于标识画像数据的时间点 | +| update_time | DATETIME | 更新时间,记录数据更新的时间戳 | + +### Java实体类 + +`CatalogEntityProfile`类定义了画像数据的Java实体模型,与数据库表结构对应: + +```java +@Data +@TableName("dv_catalog_entity_profile") +public class CatalogEntityProfile implements Serializable { + private Long id; + private String entityUuid; + private String metricName; + private String actualValue; + private String actualValueType; + private String dataDate; + private LocalDateTime updateTime; +} +``` + +### 存储配置 + +系统通过`MetricConstants`类定义了画像数据的列配置,包括`PROFILE_COLUMN_LIST`常量,用于指定画像数据的列信息: + +```java +public static final List PROFILE_COLUMN_LIST = new ArrayList<>(); + +static { + PROFILE_COLUMN_LIST.add(new ColumnInfo("entity_uuid",true, false)); + PROFILE_COLUMN_LIST.add(new ColumnInfo("metric_name",false, false)); + PROFILE_COLUMN_LIST.add(new ColumnInfo("actual_value",true, false)); + PROFILE_COLUMN_LIST.add(new ColumnInfo("actual_value_type",true, false)); + PROFILE_COLUMN_LIST.add(new ColumnInfo("data_date",false, false)); + PROFILE_COLUMN_LIST.add(new ColumnInfo("update_time",false, false)); +} +``` + +```mermaid +erDiagram +dv_catalog_entity_profile { +BIGINT id PK +VARCHAR entity_uuid FK +VARCHAR metric_name +VARCHAR actual_value +VARCHAR actual_value_type +VARCHAR data_date +DATETIME update_time +} +dv_catalog_entity_instance ||--o{ dv_catalog_entity_profile : "has" +``` + +**Diagram sources** +- [CatalogEntityProfile.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityProfile.java#L1-L57) +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java#L1-L64) + +**Section sources** +- [CatalogEntityProfile.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityProfile.java#L1-L57) +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java#L1-L64) + +## 画像任务配置与触发 + +DataVines提供了灵活的配置方式来触发数据画像任务,支持通过API接口和配置文件两种方式。 + +### API接口触发 + +系统提供了RESTful API接口来创建和更新数据画像调度任务。主要接口包括: + +- **创建或更新画像调度任务**:`POST /api/v1/catalog/profile/schedule/createOrUpdate` +- **根据实体UUID获取画像调度**:`GET /api/v1/catalog/profile/schedule/{uuid}` +- **获取周期执行的Cron表达式**:`POST /api/v1/catalog/profile/schedule/cron` + +请求参数`CatalogProfileScheduleCreateOrUpdate`包含以下字段: +- `id`:调度任务ID(可选) +- `entityUUID`:实体UUID,标识要进行画像的表 +- `type`:调度类型,定义任务的执行周期 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "CatalogEntityProfileScheduleController" +participant Service as "CatalogEntityProfileService" +Client->>Controller : POST /catalog/profile/schedule/createOrUpdate +Controller->>Service : createOrUpdate(createOrUpdate) +Service->>Service : 创建或更新画像调度 +Service-->>Controller : 返回结果 +Controller-->>Client : 返回响应 +``` + +**Diagram sources** +- [CatalogProfileScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/catalog/profile/CatalogProfileScheduleCreateOrUpdate.java#L1-L37) +- [CatalogEntityProfileScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogEntityProfileScheduleController.java#L19-L65) + +### 任务执行参数 + +数据画像任务支持配置执行参数,包括选择要分析的列和过滤条件。`RunProfileRequest`类定义了任务执行的请求参数: + +```java +@Data +public class RunProfileRequest { + private String uuid; // 实体UUID + private boolean selectAll; // 是否选择所有列 + private List selectedColumnList; // 选择的列列表 + private String filter; // 过滤条件 +} +``` + +当`selectAll`为`true`时,系统将对所有列执行画像分析;当为`false`时,仅对`selectedColumnList`中指定的列执行分析。`filter`参数可用于指定数据过滤条件,只对满足条件的数据进行分析。 + +**Section sources** +- [RunProfileRequest.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/catalog/profile/RunProfileRequest.java#L1-L36) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L829-L888) + +## 画像结果展示 + +DataVines在数据目录中提供了丰富的可视化展示方式,帮助用户直观地理解数据画像结果。 + +### 趋势图展示 + +系统支持展示表行数的趋势图,帮助用户监控数据量的变化趋势。趋势图显示了历史数据量的变化情况,可以识别数据增长或减少的模式。 + +### 分布图展示 + +对于分类数据和数值数据,系统提供分布图展示,包括: +- **柱状图**:显示不同值的出现频次 +- **直方图**:显示数值数据的分布情况 +- **饼图**:显示各类别数据的占比 + +### 详细指标展示 + +在数据目录的列详情页面,系统展示详细的画像指标,包括: +- **基础信息**:列名、数据类型 +- **空值统计**:空值数量和百分比 +- **唯一值统计**:唯一值数量和百分比 +- **极值统计**:最大值和最小值 +- **统计指标**:平均值、总和、标准差、方差(数值类型) +- **长度统计**:平均长度、最大长度、最小长度(字符串类型) + +```mermaid +graph TD +A[画像结果展示] --> B[趋势图] +A --> C[分布图] +A --> D[详细指标] +B --> B1[行数趋势] +B --> B2[指标趋势] +C --> C1[柱状图] +C --> C2[直方图] +C --> C3[饼图] +D --> D1[基础信息] +D --> D2[空值统计] +D --> D3[唯一值统计] +D --> D4[极值统计] +D --> D5[统计指标] +D --> D6[长度统计] +``` + +**Section sources** +- [profileContent.tsx](file://datavines-ui/Editor/components/Database/profileContent.tsx#L1-L195) + +## 使用场景 + +DataVines的数据画像功能在多种场景下都有重要应用价值。 + +### 数据探索 + +数据画像为数据探索提供了全面的起点。通过查看数据的基本统计特征,数据分析师可以快速了解数据的结构、分布和质量状况,为后续的分析工作奠定基础。例如,通过查看空值率,可以识别数据质量问题;通过查看唯一值率,可以判断列是否适合作为主键。 + +### 数据质量基线建立 + +数据画像可以帮助建立数据质量基线。通过定期执行数据画像任务,可以收集历史数据特征,建立正常范围的基线。当后续的数据特征偏离基线时,可以及时发现数据质量问题。例如,如果某列的空值率突然显著增加,可能表明数据采集或处理过程中出现了问题。 + +### 数据异常检测 + +基于数据画像结果,可以实现数据异常检测。系统可以配置异常检测规则,当某些指标超出预设阈值时触发告警。例如: +- 表行数突然减少超过50% +- 某列的空值率超过10% +- 数值列的标准差显著增加 + +这些异常检测可以帮助数据团队及时发现和响应数据问题,保障数据的可靠性和一致性。 + +```mermaid +flowchart TD +A[数据画像] --> B[数据探索] +A --> C[质量基线] +A --> D[异常检测] +B --> B1[了解数据结构] +B --> B2[识别数据分布] +B --> B3[发现数据问题] +C --> C1[建立历史基线] +C --> C2[定义正常范围] +C --> C3[持续监控] +D --> D1[设置阈值] +D --> D2[实时监控] +D --> D3[触发告警] +``` + +## 执行引擎支持 + +DataVines支持多种执行引擎来运行数据画像任务,提供了灵活性和可扩展性。 + +### Spark引擎 + +Spark引擎适用于大规模数据处理场景。系统通过`SparkEngineExecutor`类实现Spark引擎的执行逻辑,使用`spark-submit`命令提交任务到Spark集群。Spark引擎支持以下配置参数: +- 部署模式(deploy mode) +- Driver核心数和内存 +- Executor数量、核心数和内存 +- 其他Spark配置 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Server as "DataVines服务器" +participant Spark as "Spark集群" +Client->>Server : 提交画像任务 +Server->>Server : 生成Spark任务配置 +Server->>Spark : spark-submit提交任务 +Spark->>Spark : 执行数据画像 +Spark-->>Server : 返回执行结果 +Server-->>Client : 返回画像结果 +``` + +**Diagram sources** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L1-L153) + +### Local引擎 + +Local引擎是基于JDBC的本地执行引擎,不依赖外部执行环境。它适用于小规模数据处理和开发测试场景。Local引擎直接通过JDBC连接数据源执行SQL查询,获取画像结果。 + +### Flink引擎 + +系统也支持Flink引擎,通过`FlinkEngineExecutor`实现。Flink引擎适用于流式数据处理场景,可以实时监控数据特征的变化。 + +不同执行引擎的选择应根据数据规模、性能要求和基础设施条件来决定。对于大规模数据处理,推荐使用Spark引擎;对于小规模数据或开发测试,可以使用Local引擎。 + +**Section sources** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L1-L153) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L27-L57) +- [README.md](file://README.md#L73-L74) + +## 使用示例 + +### 为特定表配置画像任务 + +要为特定表配置数据画像任务,可以通过API接口发送请求: + +```json +{ + "entityUUID": "table-uuid-123", + "type": "DAILY" +} +``` + +此请求将为指定UUID的表创建每日执行的数据画像调度任务。 + +### 查询历史画像数据 + +可以通过以下API查询特定实体的历史画像数据: + +```http +GET /api/v1/catalog/profile/table/{uuid} +``` + +或查询特定列的画像数据: + +```http +GET /api/v1/catalog/profile/column/{uuid} +``` + +### 执行即时画像任务 + +要立即执行一次数据画像任务,可以使用`RunProfileRequest`: + +```json +{ + "uuid": "table-uuid-123", + "selectAll": true, + "filter": "date > '2023-01-01'" +} +``` + +此请求将立即对指定表的所有列执行画像分析,但仅分析日期大于2023年1月1日的数据。 + +**Section sources** +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L829-L888) +- [CatalogProfileScheduleCreateOrUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/catalog/profile/CatalogProfileScheduleCreateOrUpdate.java#L1-L37) + +## 常见问题 + +### 画像任务性能优化 + +对于大规模数据的画像任务,性能可能成为瓶颈。以下是一些性能优化建议: +- **采样分析**:对于超大规模数据,可以考虑使用采样数据进行分析,以提高执行速度 +- **增量分析**:只分析新增或变化的数据,而不是全量分析 +- **合理配置资源**:根据数据规模合理配置Spark引擎的资源参数,如Executor数量和内存 +- **索引优化**:确保被分析的列有适当的数据库索引,以加快查询速度 + +### 大规模数据处理 + +处理大规模数据时,需要注意以下几点: +- **内存管理**:避免一次性加载过多数据到内存,使用流式处理或分页查询 +- **超时设置**:适当增加任务超时时间,避免因执行时间过长而导致任务失败 +- **分布式处理**:利用Spark等分布式计算引擎的并行处理能力,提高处理效率 +- **数据分区**:如果数据有自然的时间或业务分区,可以按分区进行分析,降低单次处理的数据量 + +通过合理配置和优化,DataVines可以有效处理大规模数据的画像任务,满足不同场景下的性能要求。 + +**Section sources** +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L974-L991) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L1-L153) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\347\211\271\345\276\201\346\214\207\346\240\207.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\347\211\271\345\276\201\346\214\207\346\240\207.md" new file mode 100644 index 00000000..1fe38689 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\347\211\271\345\276\201\346\214\207\346\240\207.md" @@ -0,0 +1,176 @@ +# 特征指标 + + +**本文档中引用的文件** +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java) +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java) +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java) +- [BaseSingleTableColumn.java](file://datavines-metric/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumn.java) +- [TableRowCountMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/table/TableRowCountMetric.java) +- [NullMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/column/NullMetric.java) +- [UniqueMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-unique/src/main/java/io/datavines/metric/plugin/column/UniqueMetric.java) +- [MaxMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-max/src/main/java/io/datavines/metric/plugin/column/MaxMetric.java) +- [MinMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-min/src/main/java/io/datavines/metric/plugin/column/MinMetric.java) +- [AvgMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-avg/src/main/java/io/datavines/metric/plugin/column/AvgMetric.java) +- [StdDevMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-std-dev/src/main/java/io/datavines/metric/plugin/column/StdDevMetric.java) +- [HistogramMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-histogram/src/main/java/io/datavines/metric/plugin/column/HistogramMetric.java) + + +## 目录 +1. [引言](#引言) +2. [核心特征指标详解](#核心特征指标详解) +3. [指标计算方法与业务意义](#指标计算方法与业务意义) +4. [适用数据类型与场景](#适用数据类型与场景) +5. [算法实现细节](#算法实现细节) +6. [执行引擎差异](#执行引擎差异) +7. [指标关联与组合使用](#指标关联与组合使用) +8. [实际案例分析](#实际案例分析) +9. [性能优化策略](#性能优化策略) +10. [结论](#结论) + +## 引言 +DataVines 是一个数据质量监控平台,提供丰富的数据画像特征指标来评估和监控数据质量。本文档详细解释 DataVines 支持的各项数据特征指标,包括行数统计、列类型识别、数据分布、空值率、唯一值率、最大值、最小值、平均值、标准差等指标的计算方法和业务意义。同时,本文档还说明了每种指标适用的数据类型和场景,提供了指标计算的算法实现细节,包括在不同执行引擎(Spark、Flink、Local)中的实现差异。此外,本文档还解释了指标之间的关联关系和组合使用方式,并提供了实际案例展示如何利用这些指标进行数据质量分析和异常检测。最后,本文档解决了指标计算过程中的性能优化问题,如大数据量下的采样策略。 + +## 核心特征指标详解 + +### 行数统计 +行数统计指标用于计算表中的总行数,反映数据集的规模。该指标适用于所有类型的数据表,是评估数据完整性的重要基础指标。 + +**节来源** +- [TableRowCountMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/table/TableRowCountMetric.java#L1-L50) + +### 空值率 +空值率指标计算某一列中空值(NULL)所占的比例,用于评估数据的完整性。高空值率可能表明数据采集或传输过程中存在问题。 + +**节来源** +- [NullMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/column/NullMetric.java#L1-L50) + +### 唯一值率 +唯一值率指标计算某一列中唯一值所占的比例,用于评估数据的唯一性。低唯一值率可能表明数据存在大量重复,影响数据质量。 + +**节来源** +- [UniqueMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-unique/src/main/java/io/datavines/metric/plugin/column/UniqueMetric.java#L1-L50) + +### 最大值 +最大值指标计算某一列中的最大数值,用于了解数据的上限。该指标适用于数值型数据,帮助识别异常高的数据点。 + +**节来源** +- [MaxMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-max/src/main/java/io/datavines/metric/plugin/column/MaxMetric.java#L1-L50) + +### 最小值 +最小值指标计算某一列中的最小数值,用于了解数据的下限。该指标适用于数值型数据,帮助识别异常低的数据点。 + +**节来源** +- [MinMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-min/src/main/java/io/datavines/metric/plugin/column/MinMetric.java#L1-L50) + +### 平均值 +平均值指标计算某一列中所有数值的算术平均值,用于了解数据的集中趋势。该指标适用于数值型数据,是评估数据质量的重要指标。 + +**节来源** +- [AvgMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-avg/src/main/java/io/datavines/metric/plugin/column/AvgMetric.java#L1-L50) + +### 标准差 +标准差指标计算某一列中所有数值的标准差,用于了解数据的离散程度。高标准差表明数据分布较广,可能存在异常值。 + +**节来源** +- [StdDevMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-std-dev/src/main/java/io/datavines/metric/plugin/column/StdDevMetric.java#L1-L50) + +### 数据分布 +数据分布指标通过直方图等方式展示某一列中数据的分布情况,帮助理解数据的整体形态。该指标适用于数值型和类别型数据。 + +**节来源** +- [HistogramMetric.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-histogram/src/main/java/io/datavines/metric/plugin/column/HistogramMetric.java#L1-L50) + +## 指标计算方法与业务意义 + +### 计算方法 +DataVines 中的各项指标主要通过 SQL 查询实现。例如,行数统计通过 `COUNT(*)` 实现,空值率通过 `COUNT(*) - COUNT(column)` 与 `COUNT(*)` 的比值实现,唯一值率通过 `COUNT(DISTINCT column)` 与 `COUNT(*)` 的比值实现,最大值和最小值分别通过 `MAX(column)` 和 `MIN(column)` 实现,平均值通过 `AVG(column)` 实现,标准差通过 `STDDEV(column)` 实现。 + +### 业务意义 +这些指标在数据质量管理中具有重要的业务意义。行数统计帮助监控数据量的变化,空值率和唯一值率帮助评估数据的完整性和唯一性,最大值、最小值、平均值和标准差帮助了解数据的分布特征,数据分布直方图帮助可视化数据的整体形态。通过这些指标,可以及时发现数据质量问题,采取相应的措施进行改进。 + +**节来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L1-L112) +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java#L1-L50) +- [BaseSingleTableColumn.java](file://datavines-metric/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumn.java#L1-L50) + +## 适用数据类型与场景 + +### 数值型数据 +对于数值型数据,适用的指标包括最大值、最小值、平均值、标准差、数据分布等。这些指标帮助了解数值型数据的集中趋势和离散程度。 + +### 类别型数据 +对于类别型数据,适用的指标包括唯一值率、数据分布等。这些指标帮助了解类别型数据的多样性和分布情况。 + +### 时间型数据 +对于时间型数据,适用的指标包括最大值、最小值、数据分布等。这些指标帮助了解时间型数据的时间范围和分布特征。 + +**节来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L94-L98) + +## 算法实现细节 + +### 基础实现 +DataVines 中的指标计算基于 `SqlMetric` 接口实现。每个具体的指标实现类都继承自 `BaseSingleTable` 或 `BaseSingleTableColumn`,并实现 `SqlMetric` 接口中的方法。通过 `getActualValue` 方法生成计算指标的 SQL 查询语句。 + +### 扩展实现 +对于复杂的指标计算,可以通过自定义 SQL 实现。DataVines 提供了 `SINGLE_TABLE_CUSTOM_SQL` 类型的指标,允许用户编写自定义的 SQL 查询来计算特定的指标。 + +**节来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L59-L67) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java#L31-L34) + +## 执行引擎差异 + +### Spark +在 Spark 引擎中,指标计算通过 Spark SQL 实现。Spark 的分布式计算能力使得大规模数据的指标计算更加高效。 + +### Flink +在 Flink 引擎中,指标计算通过 Flink SQL 实现。Flink 的流处理能力使得实时数据的指标计算成为可能。 + +### Local +在 Local 模式下,指标计算通过本地 JDBC 连接实现。适用于小规模数据的快速验证和测试。 + +**节来源** +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java#L31-L34) + +## 指标关联与组合使用 + +### 关联关系 +不同的指标之间存在一定的关联关系。例如,空值率和唯一值率可以结合使用,评估数据的完整性和唯一性;最大值、最小值、平均值和标准差可以结合使用,全面了解数据的分布特征。 + +### 组合使用 +通过组合使用多个指标,可以构建更复杂的数据质量评估模型。例如,可以结合行数统计、空值率、唯一值率等指标,构建数据完整性评估模型;结合最大值、最小值、平均值、标准差等指标,构建数据分布评估模型。 + +**节来源** +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java#L24-L38) + +## 实际案例分析 + +### 案例一:电商订单数据质量分析 +在电商订单数据中,通过行数统计监控每日订单量的变化,通过空值率评估订单信息的完整性,通过唯一值率评估订单ID的唯一性,通过最大值、最小值、平均值和标准差了解订单金额的分布特征。通过这些指标的组合使用,可以全面评估电商订单数据的质量。 + +### 案例二:用户行为日志数据质量分析 +在用户行为日志数据中,通过行数统计监控每日日志量的变化,通过空值率评估日志字段的完整性,通过数据分布直方图了解用户行为的时间分布特征。通过这些指标的组合使用,可以及时发现日志数据中的异常情况。 + +**节来源** +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java#L57-L74) + +## 性能优化策略 + +### 采样策略 +对于大规模数据,直接计算所有指标可能会导致性能问题。DataVines 提供了采样策略,通过随机采样部分数据来估算指标值,从而提高计算效率。 + +### 并行计算 +利用 Spark 和 Flink 的分布式计算能力,将指标计算任务并行化,提高计算速度。 + +### 缓存机制 +对于频繁计算的指标,可以使用缓存机制,避免重复计算,提高响应速度。 + +**节来源** +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java#L1-L50) + +## 结论 +DataVines 提供了丰富的数据画像特征指标,帮助用户全面评估和监控数据质量。通过合理使用这些指标,可以及时发现数据质量问题,采取相应的措施进行改进。同时,DataVines 还提供了灵活的算法实现和性能优化策略,适应不同规模和场景的数据质量监控需求。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\345\217\202\346\225\260\350\257\264\346\230\216.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\345\217\202\346\225\260\350\257\264\346\230\216.md" new file mode 100644 index 00000000..8e7947f8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\345\217\202\346\225\260\350\257\264\346\230\216.md" @@ -0,0 +1,512 @@ +# 参数说明 + + +**本文档引用的文件** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [SourceConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SourceConfig.java) +- [SinkConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SinkConfig.java) +- [TransformConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/TransformConfig.java) +- [BaseConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/BaseConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java) +- [submit_job_file_source.json](file://datavines-runner/src/main/resources/submit_job_file_source.json) +- [submit_job_file_storage.json](file://datavines-runner/src/main/resources/submit_job_file_storage.json) +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java) +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java) +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) + + +## 目录 +1. [引言](#引言) +2. [核心配置参数](#核心配置参数) +3. [数据源配置](#数据源配置) +4. [采集模式与频率](#采集模式与频率) +5. [采样率配置](#采样率配置) +6. [目标表选择](#目标表选择) +7. [高级参数配置](#高级参数配置) +8. [资源限制与超时设置](#资源限制与超时设置) +9. [重试策略](#重试策略) +10. [JSON配置模板](#json配置模板) +11. [参数依赖关系与约束](#参数依赖关系与约束) +12. [最佳实践与推荐值](#最佳实践与推荐值) + +## 引言 + +数据画像采集系统提供了一套完整的配置参数体系,用于控制数据质量检查、数据画像生成和数据验证的各个方面。本参数说明文档全面解释了所有配置参数的含义和用法,详细描述了采集频率、采样率、目标表选择、采集模式(增量/全量)等核心参数的配置方法和取值范围。 + +系统采用分层配置结构,主要由作业配置(DataVinesJobConfig)、环境配置(EnvConfig)、数据源配置(SourceConfig)、转换配置(TransformConfig)和接收器配置(SinkConfig)组成。每个配置参数都经过严格验证,确保配置的正确性和完整性。 + +**本节内容未分析具体源文件,因此不提供来源信息** + +## 核心配置参数 + +核心配置参数构成了数据画像采集任务的基础结构,定义了任务的基本属性和执行环境。`DataVinesJobConfig`类是核心配置的载体,包含任务名称、环境配置、数据源、转换和接收器等关键组件。 + +```mermaid +classDiagram +class DataVinesJobConfig { ++String name ++EnvConfig envConfig ++List sourceParameters ++List transformParameters ++List sinkParameters ++validate() void ++toString() String +} +class EnvConfig { ++String engine ++String type ++Map config ++validate() void +} +class SourceConfig { ++String plugin ++String type ++Map config +} +class TransformConfig { ++String plugin ++String type ++Map config +} +class SinkConfig { ++String plugin ++String type ++Map config +} +DataVinesJobConfig --> EnvConfig : "包含" +DataVinesJobConfig --> SourceConfig : "包含多个" +DataVinesJobConfig --> TransformConfig : "包含多个" +DataVinesJobConfig --> SinkConfig : "包含多个" +SourceConfig --> BaseConfig : "继承" +TransformConfig --> BaseConfig : "继承" +SinkConfig --> BaseConfig : "继承" +``` + +**图示来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java#L26-L130) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java#L29-L80) +- [SourceConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SourceConfig.java#L24-L36) +- [TransformConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/TransformConfig.java#L24-L36) +- [SinkConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SinkConfig.java#L24-L36) + +**本节来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java#L26-L130) +- [BaseConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/BaseConfig.java#L29-L85) + +## 数据源配置 + +数据源配置通过`SourceConfig`类实现,该类继承自`BaseConfig`,提供了统一的插件化配置接口。数据源配置的核心参数包括插件类型、数据源类型和具体配置参数。 + +`SourceConfig`的主要参数如下: +- **plugin**: 指定数据源插件类型,如"mysql"、"postgresql"、"oracle"等 +- **type**: 指定数据源的具体类型 +- **config**: 包含具体的数据源连接参数,如主机地址、端口、用户名、密码等 + +数据源配置支持多种数据库类型,包括关系型数据库(MySQL、PostgreSQL、Oracle等)和文件系统。配置参数通过Map结构存储,提供了良好的扩展性和灵活性。 + +```mermaid +classDiagram +class BaseConfig { ++String plugin ++String type ++Map config ++validate() void +} +class SourceConfig { ++SourceConfig() ++SourceConfig(String plugin, Map config) ++SourceConfig(String plugin, String type, Map config) +} +SourceConfig --> BaseConfig : "继承" +``` + +**图示来源** +- [SourceConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SourceConfig.java#L24-L36) +- [BaseConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/BaseConfig.java#L29-L85) + +**本节来源** +- [SourceConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SourceConfig.java#L24-L36) +- [BaseConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/BaseConfig.java#L29-L85) + +## 采集模式与频率 + +采集模式和频率通过环境配置(EnvConfig)进行控制,是影响数据采集行为的关键参数。`EnvConfig`类定义了执行引擎、执行类型和相关配置参数。 + +### 采集模式 + +采集模式由`type`参数控制,支持以下两种模式: +- **batch**: 批处理模式,适用于全量数据采集和周期性数据质量检查 +- **stream**: 流式处理模式,适用于实时数据监控和增量数据采集 + +批处理模式适合对历史数据进行全面分析,而流式处理模式适合对实时数据进行持续监控。选择合适的采集模式对系统性能和数据时效性有重要影响。 + +### 采集频率 + +采集频率通过调度系统配置,通常与作业的调度周期相关。虽然采集频率参数不直接在`EnvConfig`中定义,但通过`config`参数可以传递与频率相关的配置信息。 + +```mermaid +classDiagram +class EnvConfig { ++String engine ++String type ++Map config ++validate() void +} +note right of EnvConfig +type参数控制采集模式: +- batch : 批处理模式 +- stream : 流式处理模式 +end note +``` + +**图示来源** +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java#L29-L80) + +**本节来源** +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java#L29-L80) + +## 采样率配置 + +采样率配置是控制数据采集量的重要参数,直接影响采集性能和结果的代表性。虽然在核心配置类中没有直接的采样率参数,但可以通过`config`参数在数据源或转换配置中传递采样率设置。 + +采样率通常以百分比形式表示,取值范围为0-100。0表示不采集任何数据,100表示全量采集。合理的采样率设置可以在保证数据代表性的同时,显著降低系统资源消耗。 + +在实际应用中,采样率配置通常与采集频率和数据量大小相权衡。对于数据量较大的表,可以适当降低采样率以提高采集效率;对于关键业务表,则应提高采样率以确保数据质量。 + +**本节内容未分析具体源文件,因此不提供来源信息** + +## 目标表选择 + +目标表选择通过数据源配置中的具体参数实现,通常在`config`参数中指定。在示例配置文件`submit_job_file_source.json`中,可以看到目标表选择的具体实现方式。 + +目标表选择参数包括: +- **table_name**: 指定要采集的目标表名称 +- **database**: 指定目标数据库名称 +- **schema**: 指定数据表的结构信息 + +目标表选择支持单表和多表配置。对于多表采集,可以在数据源配置中指定多个表,或通过通配符匹配多个表。选择合适的目标表对数据画像的准确性和完整性至关重要。 + +```mermaid +flowchart TD +Start["开始配置目标表"] --> TableName["指定表名
table_name参数"] +TableName --> Database["指定数据库
database参数"] +Database --> Schema["指定表结构
schema参数"] +Schema --> Validation["验证表存在性"] +Validation --> MultipleTables{"是否多表采集?"} +MultipleTables --> |是| Wildcard["使用通配符匹配"] +MultipleTables --> |否| SingleTable["单表配置"] +Wildcard --> End["完成配置"] +SingleTable --> End +``` + +**图示来源** +- [submit_job_file_source.json](file://datavines-runner/src/main/resources/submit_job_file_source.json#L9-L12) + +**本节来源** +- [submit_job_file_source.json](file://datavines-runner/src/main/resources/submit_job_file_source.json#L9-L12) + +## 高级参数配置 + +高级参数配置涵盖了数据采集过程中的各种精细化控制选项,包括通知配置、错误数据存储和验证结果存储等。这些参数在示例配置文件`submit_job_file_storage.json`中有详细体现。 + +### 通知参数 + +通知参数用于配置数据质量检查结果的通知方式,支持多种通知渠道: +- **email**: 邮件通知 +- **dingtalk**: 钉钉通知 +- **lark**: 飞书通知 +- **wecombot**: 企业微信通知 + +每种通知方式都有相应的配置参数,如邮件服务器地址、端口、发件人、收件人等。 + +### 存储参数 + +存储参数用于配置错误数据和验证结果的存储位置: +- **errorDataStorageType**: 错误数据存储类型 +- **errorDataStorageParameter**: 错误数据存储参数 +- **validateResultDataStorageType**: 验证结果存储类型 +- **validateResultDataStorageParameter**: 验证结果存储参数 + +```mermaid +classDiagram +class NotificationConfig { ++String type ++Map config ++Map receiver +} +class StorageConfig { ++String data_dir ++String column_separator +} +class JobConfig { ++List notificationParameters ++String errorDataStorageType ++StorageConfig errorDataStorageParameter ++String validateResultDataStorageType ++StorageConfig validateResultDataStorageParameter +} +JobConfig --> NotificationConfig : "包含多个" +JobConfig --> StorageConfig : "包含" +``` + +**图示来源** +- [submit_job_file_storage.json](file://datavines-runner/src/main/resources/submit_job_file_storage.json#L46-L64) + +**本节来源** +- [submit_job_file_storage.json](file://datavines-runner/src/main/resources/submit_job_file_storage.json#L36-L64) + +## 资源限制与超时设置 + +资源限制与超时设置是保障系统稳定运行的重要参数,通过执行引擎的配置参数进行控制。不同执行引擎有不同的资源限制参数。 + +### Spark引擎资源限制 + +对于Spark引擎,资源限制参数包括: +- **numExecutors**: 执行器数量 +- **executorCores**: 每个执行器的核心数 +- **executorMemory**: 每个执行器的内存 +- **driverCores**: 驱动程序核心数 +- **driverMemory**: 驱动程序内存 + +这些参数在`SparkEngineParameter`类中定义,用于控制Spark作业的资源分配。 + +### Flink引擎资源限制 + +对于Flink引擎,资源限制参数包括: +- **taskManagerCount**: TaskManager数量 +- **taskManagerMemory**: TaskManager内存 +- **jobManagerMemory**: JobManager内存 +- **parallelism**: 并行度 + +这些参数在`FlinkParameters`类中定义,用于控制Flink作业的资源分配。 + +```mermaid +classDiagram +class SparkEngineParameter { ++String programType ++String deployMode ++int driverCores ++String driverMemory ++int numExecutors ++int executorCores ++String executorMemory ++String others +} +class FlinkParameters { ++String taskManagerCount ++String taskManagerMemory ++String jobManagerMemory ++int parallelism ++String flinkOthers +} +note right of SparkEngineParameter +Spark引擎资源参数 +end note +note right of FlinkParameters +Flink引擎资源参数 +end note +``` + +**图示来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L26-L68) +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) + +**本节来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L26-L68) +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) + +## 重试策略 + +重试策略通过`TimeoutStrategy`枚举类定义,用于控制任务执行失败时的处理方式。系统提供了两种重试策略: + +- **RETRY (0)**: 重试策略,当任务失败时尝试重新执行 +- **WARN (1)**: 警告策略,当任务失败时记录警告但继续执行后续任务 + +重试策略的选择应根据任务的重要性和失败影响来决定。对于关键业务任务,建议使用RETRY策略以确保任务最终成功;对于非关键任务,可以使用WARN策略以避免阻塞整个作业流程。 + +```mermaid +stateDiagram-v2 +[*] --> RETRY +[*] --> WARN +RETRY --> "任务失败" : 发生 +"任务失败" --> "尝试重试" : RETRY策略 +"尝试重试" --> "任务成功" : 重试成功 +"尝试重试" --> "任务失败" : 重试失败 +"任务成功" --> [*] +WARN --> "任务失败" : 发生 +"任务失败" --> "记录警告" : WARN策略 +"记录警告" --> "继续执行" +"继续执行" --> [*] +``` + +**图示来源** +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java#L24-L50) + +**本节来源** +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java#L24-L50) + +## JSON配置模板 + +以下是一个完整的JSON配置模板,包含所有可配置项的示例和注释: + +```json +{ + "name": "数据画像采集任务", + "env": { + "engine": "spark", + "type": "batch", + "config": { + "spark.engine.parameter.num.executors": 2, + "spark.engine.parameter.executor.cores": 2, + "spark.engine.parameter.executor.memory": "1g" + } + }, + "sources": [ + { + "plugin": "mysql", + "type": "database", + "config": { + "host": "localhost", + "port": "3306", + "user": "root", + "password": "password", + "database": "test", + "table_name": "user_info", + "schema": "id,name,age,email" + } + } + ], + "transforms": [ + { + "plugin": "data_profile", + "type": "profile", + "config": { + "sampling_rate": 100, + "metrics": ["row_count", "column_null", "column_duplicate"] + } + } + ], + "sinks": [ + { + "plugin": "file", + "type": "storage", + "config": { + "data_dir": "/tmp/datavines/results", + "column_separator": "," + } + } + ], + "errorDataStorageType": "file", + "errorDataStorageParameter": { + "data_dir": "/tmp/datavines/errors", + "column_separator": "," + }, + "validateResultDataStorageType": "file", + "validateResultDataStorageParameter": { + "data_dir": "/tmp/datavines/validate_results", + "column_separator": "," + }, + "notificationParameters": [ + { + "type": "email", + "config": { + "serverHost": "smtp.gmail.com", + "serverPort": "587", + "sender": "sender@gmail.com", + "user": "sender@gmail.com", + "passwd": "password", + "starttlsEnable": "true" + }, + "receiver": { + "to": "receiver@gmail.com" + } + } + ] +} +``` + +**本节来源** +- [submit_job_file_source.json](file://datavines-runner/src/main/resources/submit_job_file_source.json) +- [submit_job_file_storage.json](file://datavines-runner/src/main/resources/submit_job_file_storage.json) + +## 参数依赖关系与约束 + +参数之间存在复杂的依赖关系和约束条件,正确理解这些关系对配置的正确性至关重要。 + +### 采样率与采集频率的权衡 + +采样率和采集频率之间存在明显的权衡关系: +- 高采样率+高采集频率:数据代表性好,但系统负载高 +- 低采样率+低采集频率:系统负载低,但数据代表性差 +- 高采样率+低采集频率:适合关键业务表的定期全面检查 +- 低采样率+高采集频率:适合非关键业务表的持续监控 + +### 引擎与资源参数的约束 + +执行引擎与资源参数之间存在严格的约束关系: +- Spark引擎需要配置executor和driver相关参数 +- Flink引擎需要配置TaskManager和JobManager相关参数 +- 不同引擎的参数不能混用 + +### 数据源与目标表的约束 + +数据源配置与目标表选择之间存在依赖关系: +- 数据源类型决定了可用的目标表选择方式 +- 数据库连接参数必须正确才能访问目标表 +- 表结构信息必须与实际表结构匹配 + +```mermaid +graph TD +A[采样率] --> B[系统负载] +C[采集频率] --> B[系统负载] +B --> D[数据代表性] +E[Spark引擎] --> F[executor参数] +E --> G[driver参数] +H[Flink引擎] --> I[TaskManager参数] +H --> J[JobManager参数] +K[数据源类型] --> L[目标表选择] +M[连接参数] --> N[表访问] +``` + +**本节内容未分析具体源文件,因此不提供来源信息** + +## 最佳实践与推荐值 + +基于系统特性和实际应用经验,以下是数据画像采集参数的最佳实践和推荐值: + +### 一般性推荐 + +- **任务命名**: 使用有意义的名称,便于识别和管理 +- **配置验证**: 在提交任务前进行配置验证,确保所有必填参数都已设置 +- **参数注释**: 对复杂配置添加注释,便于后续维护 + +### 采集模式推荐 + +- **批处理模式**: 适用于每日/每周的数据质量检查 +- **流式处理模式**: 适用于实时数据监控和告警 + +### 采样率推荐 + +- **关键业务表**: 采样率100%,确保数据完整性 +- **大表**: 采样率10-50%,平衡性能和代表性 +- **非关键表**: 采样率5-10%,降低系统负载 + +### 资源配置推荐 + +- **Spark作业**: + - executor数量: 2-4 + - 每个executor核心数: 2-4 + - executor内存: 2-4g +- **Flink作业**: + - TaskManager数量: 2-4 + - 并行度: 4-8 + +### 超时与重试策略 + +- **关键任务**: 使用RETRY策略,设置合理的重试次数 +- **非关键任务**: 使用WARN策略,避免阻塞作业流程 +- **超时时间**: 根据数据量和复杂度设置,一般为5-30分钟 + +**本节内容未分析具体源文件,因此不提供来源信息** \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256.md" new file mode 100644 index 00000000..0ddb1d6c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256.md" @@ -0,0 +1,249 @@ +# 执行引擎配置 + + +**本文档引用的文件** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [SparkParameters.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) +- [FlinkParameters.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java) +- [FlinkArgsUtils.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细说明了Datavines平台中Spark、Flink和Local三种执行引擎的特定配置要求。文档涵盖了每种引擎的配置文件结构差异、特有的配置参数和优化选项,提供了资源配置建议,包括内存、CPU、并行度等设置。同时,文档还说明了不同引擎在处理大规模数据时的性能特点和适用场景,并提供了针对每种引擎的最佳实践和错误处理技巧。 + +## 项目结构 +Datavines项目的结构清晰地组织了不同执行引擎的实现和配置。核心引擎实现位于`datavines-engine-plugins`目录下,每个引擎都有独立的模块,如`datavines-engine-spark`、`datavines-engine-flink`和`datavines-engine-local`。这些模块包含了引擎特定的配置、执行器和API实现。公共配置和实体定义位于`datavines-common`模块中,而配置管理逻辑则在`datavines-engine-config`模块中实现。 + +```mermaid +graph TD +subgraph "核心模块" +datavines_common["datavines-common
公共配置和实体"] +datavines_engine_config["datavines-engine-config
配置管理"] +datavines_engine_api["datavines-engine-api
引擎API"] +end +subgraph "引擎插件" +datavines_engine_spark["datavines-engine-spark
Spark引擎"] +datavines_engine_flink["datavines-engine-flink
Flink引擎"] +datavines_engine_local["datavines-engine-local
Local引擎"] +end +datavines_common --> datavines_engine_config +datavines_engine_config --> datavines_engine_api +datavines_engine_api --> datavines_engine_spark +datavines_engine_api --> datavines_engine_flink +datavines_engine_api --> datavines_engine_local +``` + +**图表来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [datavines-engine-plugins](file://datavines-engine/datavines-engine-plugins) + +## 核心组件 +本节分析Datavines平台中与执行引擎配置相关的核心组件。`SparkEngineParameter`类定义了Spark引擎的所有配置参数,包括程序类型、部署模式、驱动程序和执行器的资源分配等。`FlinkParameters`类为Flink引擎定义了类似的配置,包括任务管理器和作业管理器的内存设置。`LocalRuntimeEnvironment`类为本地执行模式提供了运行时环境,而`BaseJobConfigurationBuilder`则负责构建和管理所有引擎的配置。 + +**章节来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L1-L69) +- [FlinkParameters.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L1-L50) +- [LocalRuntimeEnvironment.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java#L1-L99) + +## 架构概述 +Datavines平台的执行引擎架构采用插件化设计,允许灵活地支持多种计算引擎。核心配置管理模块`datavines-engine-config`定义了统一的配置构建接口,而各个引擎插件则实现了具体的配置逻辑。运行时环境由`RuntimeEnvironment`接口定义,每个引擎提供自己的实现。这种设计使得平台能够轻松扩展以支持新的执行引擎,同时保持配置管理的一致性。 + +```mermaid +graph TB +subgraph "配置层" +JobConfigurationBuilder["JobConfigurationBuilder
配置构建接口"] +BaseJobConfigurationBuilder["BaseJobConfigurationBuilder
基础配置构建"] +end +subgraph "引擎层" +SparkConfig["SparkDataProfileMetricBuilder
Spark配置"] +FlinkConfig["FlinkDataProfileMetricBuilder
Flink配置"] +LocalConfig["LocalDataProfileMetricBuilder
Local配置"] +end +subgraph "运行时层" +RuntimeEnvironment["RuntimeEnvironment
运行时环境接口"] +SparkRuntime["SparkRuntimeEnvironment
Spark运行时"] +FlinkRuntime["FlinkRuntimeEnvironment
Flink运行时"] +LocalRuntime["LocalRuntimeEnvironment
Local运行时"] +end +BaseJobConfigurationBuilder --> SparkConfig +BaseJobConfigurationBuilder --> FlinkConfig +BaseJobConfigurationBuilder --> LocalConfig +RuntimeEnvironment --> SparkRuntime +RuntimeEnvironment --> FlinkRuntime +RuntimeEnvironment --> LocalRuntime +``` + +**图表来源** +- [JobConfigurationBuilder.java](file://datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java#L1-L42) +- [BaseJobConfigurationBuilder.java](file://datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L1-L322) +- [SparkRuntimeEnvironment.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java#L1-L118) + +## 详细组件分析 + +### Spark执行引擎分析 +Spark执行引擎的配置主要通过`SparkEngineParameter`和`SparkParameters`类来管理。`SparkEngineParameter`定义了Spark作业的核心配置参数,包括程序类型、部署模式、驱动程序和执行器的资源分配。`SparkParameters`类则提供了更详细的参数设置,如主JAR文件、主类、应用程序名称和YARN队列等。 + +```mermaid +classDiagram +class SparkEngineParameter { ++String programType ++String deployMode ++int driverCores ++String driverMemory ++int numExecutors ++int executorCores ++String executorMemory ++String others +} +class SparkParameters { ++String mainJar ++String mainClass ++String deployMode ++String mainArgs ++int driverCores ++String driverMemory ++int numExecutors ++int executorCores ++String executorMemory ++String appName ++String queue ++String others ++ProgramType programType ++String sparkVersion ++String jars +} +class SparkRuntimeEnvironment { +-SparkSession sparkSession +-StreamingContext streamingContext +-Config config +-boolean enableSparkHiveSupport ++void prepare() ++Execution getExecution() ++SparkSession sparkSession() ++StreamingContext streamingContext() ++boolean enableSparkHiveSupport() +} +SparkEngineParameter --> SparkParameters : "映射" +SparkParameters --> SparkRuntimeEnvironment : "使用" +``` + +**图表来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L1-L69) +- [SparkParameters.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java#L1-L220) +- [SparkRuntimeEnvironment.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java#L1-L118) + +### Flink执行引擎分析 +Flink执行引擎的配置通过`FlinkParameters`类进行管理,该类定义了Flink作业的关键参数,包括部署模式、任务管理器数量和内存、作业管理器内存、并行度等。`FlinkArgsUtils`工具类负责将这些参数转换为Flink命令行参数。 + +```mermaid +classDiagram +class FlinkParameters { ++String mainJar ++String mainClass ++String deployMode ++String taskManagerCount ++String taskManagerMemory ++String jobManagerMemory ++String mainArgs ++String yarnQueue ++String jobName ++int parallelism ++String flinkOthers ++String jars ++String tags +} +class FlinkArgsUtils { ++static final String FLINK_LOCAL = "local" ++static final String FLINK_YARN_SESSION = "yarn-session" ++static final String FLINK_YARN_PER_JOB = "yarn-per-job" ++static final String FLINK_YARN_APPLICATION = "yarn-application" ++String[] buildArgs(FlinkParameters param) +} +FlinkParameters --> FlinkArgsUtils : "参数构建" +``` + +**图表来源** +- [FlinkParameters.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L1-L50) +- [FlinkArgsUtils.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L1-L72) + +### Local执行引擎分析 +Local执行引擎的配置相对简单,主要通过`LocalRuntimeEnvironment`类提供运行时环境。该类负责管理数据库连接和执行状态,适用于小规模数据处理和测试场景。 + +```mermaid +classDiagram +class LocalRuntimeEnvironment { +-Logger log +-ConnectionHolder sourceConnection +-ConnectionHolder targetConnection +-ConnectionHolder metadataConnection +-Statement currentStatement +-boolean stop ++void prepare() ++Execution getExecution() ++void close() +} +class ConnectionHolder { +-Connection connection +-Properties properties ++void close() +} +LocalRuntimeEnvironment --> ConnectionHolder : "持有" +``` + +**图表来源** +- [LocalRuntimeEnvironment.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java#L1-L99) + +## 依赖分析 +Datavines平台的执行引擎配置依赖于多个核心模块。`datavines-common`模块提供了基础的配置实体和常量,`datavines-engine-config`模块定义了配置构建的通用接口和基类,而各个引擎插件则实现了具体的配置逻辑。这种分层设计确保了配置管理的一致性和可扩展性。 + +```mermaid +graph TD +datavines_common["datavines-common"] +datavines_engine_config["datavines-engine-config"] +datavines_engine_api["datavines-engine-api"] +datavines_engine_spark["datavines-engine-spark"] +datavines_engine_flink["datavines-engine-flink"] +datavines_engine_local["datavines-engine-local"] +datavines_common --> datavines_engine_config +datavines_engine_config --> datavines_engine_api +datavines_engine_api --> datavines_engine_spark +datavines_engine_api --> datavines_engine_flink +datavines_engine_api --> datavines_engine_local +``` + +**图表来源** +- [datavines-common](file://datavines-common) +- [datavines-engine-config](file://datavines-engine/datavines-engine-config) +- [datavines-engine-api](file://datavines-engine/datavines-engine-api) + +## 性能考虑 +在配置执行引擎时,需要根据数据规模和处理需求进行合理的资源配置。对于Spark引擎,建议根据数据量调整执行器数量和内存分配,避免内存溢出。Flink引擎的并行度设置应与集群资源相匹配,以充分利用计算能力。Local模式适用于小规模数据处理,不适合大规模生产环境。 + +## 故障排除指南 +在配置和使用执行引擎时,可能会遇到各种问题。对于Spark引擎,常见的问题包括内存不足和依赖冲突,建议通过调整`driverMemory`和`executorMemory`参数来解决。Flink引擎的常见问题包括任务管理器内存不足和网络超时,可以通过增加`taskManagerMemory`和调整检查点间隔来优化。Local模式的主要限制是资源有限,不适合处理大规模数据。 + +**章节来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L1-L69) +- [FlinkParameters.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L1-L50) +- [LocalRuntimeEnvironment.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java#L1-L99) + +## 结论 +Datavines平台通过插件化设计支持多种执行引擎,提供了灵活的配置选项。Spark引擎适合批处理和大规模数据处理,Flink引擎适合流处理和实时计算,而Local模式则适合开发和测试。通过合理配置资源和优化参数,可以充分发挥各引擎的优势,满足不同的数据处理需求。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\351\205\215\347\275\256\346\226\271\345\274\217.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\351\205\215\347\275\256\346\226\271\345\274\217.md" new file mode 100644 index 00000000..c06d2a7b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\351\205\215\347\275\256\346\226\271\345\274\217.md" @@ -0,0 +1,351 @@ +# 配置方式 + + +**本文档引用的文件** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) +- [AccessTokenController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/AccessTokenController.java) +- [JobsList.tsx](file://datavines-ui/src/view/Main/HomeDetail/Jobs/JobsList.tsx) +- [CreateConfig.tsx](file://datavines-ui/src/view/Main/Config/CreateConfig.tsx) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) +- [JobUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobUpdate.java) +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java) + + +## 目录 +1. [引言](#引言) +2. [Web界面配置方式](#web界面配置方式) +3. [API配置方式](#api配置方式) +4. [权限验证与访问控制](#权限验证与访问控制) +5. [配置方式对比与选择建议](#配置方式对比与选择建议) +6. [总结](#总结) + +## 引言 + +数据画像采集配置是数据质量管理的核心环节,本系统提供了两种主要的配置方式:Web界面配置和API配置。Web界面配置适合日常操作和可视化管理,而API配置则适用于自动化集成和批量操作。本文档将详细介绍这两种配置方式的具体步骤、参数说明和使用场景,帮助用户根据实际需求选择合适的配置方法。 + +## Web界面配置方式 + +Web界面配置提供了直观的图形化操作界面,用户可以通过浏览器完成数据画像采集任务的创建、编辑和管理。界面设计遵循用户友好的原则,将复杂的配置参数分解为多个步骤,确保用户能够轻松完成配置。 + +在Web界面中,用户首先需要选择数据源,然后配置目标表、采集频率等关键参数。界面通过分步向导的形式引导用户完成整个配置流程,每个步骤都有清晰的提示和验证机制,确保配置的准确性和完整性。 + +**Web界面配置流程:** +1. 登录系统后,进入"作业管理"页面 +2. 点击"新建作业"按钮,选择作业类型(质量检测或数据比对) +3. 在弹出的配置对话框中,选择数据源 +4. 配置作业基本信息,包括作业名称、描述等 +5. 设置执行平台和引擎参数 +6. 配置超时策略和重试机制 +7. 定义预处理和后处理SQL脚本 +8. 设置错误数据存储位置 +9. 确认配置并保存 + +界面中的每个配置项都有相应的帮助提示,用户可以通过悬停或点击问号图标查看详细的参数说明。对于关键参数,系统还提供了默认值建议,帮助用户快速完成配置。 + +**界面元素说明:** +- **数据源选择**:下拉列表,显示用户有权限访问的所有数据源 +- **作业类型**:单选按钮,选择质量检测或数据比对 +- **执行频率**:时间选择器,支持按分钟、小时、天等周期配置 +- **超时设置**:数字输入框,单位为秒,支持自定义超时时间 +- **重试机制**:开关控件,开启后可设置重试次数和间隔 +- **SQL脚本区域**:代码编辑器,支持语法高亮和自动补全 +- **错误数据处理**:复选框,选择是否将错误数据输出到指定数据源 + +**操作指引:** +1. 在作业列表页面,点击右上角的"新建"下拉菜单 +2. 选择"质量检测"或"数据比对"类型 +3. 在配置对话框中,首先选择数据源 +4. 填写作业名称,建议使用有意义的命名规则 +5. 根据业务需求,配置相应的参数 +6. 点击"测试连接"按钮验证数据源连通性 +7. 点击"预览"按钮查看生成的执行计划 +8. 确认无误后,点击"保存"按钮完成配置 + +**Section sources** +- [JobsList.tsx](file://datavines-ui/src/view/Main/HomeDetail/Jobs/JobsList.tsx#L1-L200) +- [CreateConfig.tsx](file://datavines-ui/src/view/Main/Config/CreateConfig.tsx#L1-L138) + +## API配置方式 + +API配置方式提供了RESTful接口,允许用户通过编程方式创建和管理数据画像采集任务。这种方式特别适合需要自动化集成的场景,如与CI/CD流程集成、批量创建作业等。 + +### RESTful接口说明 + +#### 创建作业 +- **HTTP方法**:POST +- **URL路径**:/api/v1/job +- **请求头**: + - Content-Type: application/json + - Authorization: Bearer {access_token} +- **请求体结构**: +```json +{ + "type": "quality", + "dataSourceId": 1, + "jobName": "用户表质量检测", + "parameter": "{\"metricType\":\"table\",\"metric\":{\"type\":\"table_row_count\",\"name\":\"表行数\"}}", + "timeout": 60000, + "timeoutStrategy": "WARN", + "retryTimes": 3, + "retryInterval": 1000, + "preSql": "DELETE FROM temp_table", + "postSql": "INSERT INTO report_table SELECT * FROM result_table", + "errorDataStorageId": 1, + "runningNow": 1 +} +``` +- **响应格式**: +```json +{ + "code": 0, + "message": "success", + "data": 123 +} +``` + +#### 更新作业 +- **HTTP方法**:PUT +- **URL路径**:/api/v1/job +- **请求头**: + - Content-Type: application/json + - Authorization: Bearer {access_token} +- **请求体结构**: +```json +{ + "id": 123, + "type": "quality", + "dataSourceId": 1, + "jobName": "更新后的作业名称", + "parameter": "{\"metricType\":\"table\",\"metric\":{\"type\":\"table_row_count\",\"name\":\"表行数\"}}" +} +``` +- **响应格式**: +```json +{ + "code": 0, + "message": "success", + "data": 1 +} +``` + +#### 删除作业 +- **HTTP方法**:DELETE +- **URL路径**:/api/v1/job/{id} +- **请求头**: + - Authorization: Bearer {access_token} +- **响应格式**: +```json +{ + "code": 0, + "message": "success", + "data": 1 +} +``` + +#### 获取作业详情 +- **HTTP方法**:GET +- **URL路径**:/api/v1/job/{id} +- **请求头**: + - Authorization: Bearer {access_token} +- **响应格式**: +```json +{ + "code": 0, + "message": "success", + "data": { + "id": 123, + "type": "quality", + "dataSourceId": 1, + "jobName": "用户表质量检测", + "parameter": "{\"metricType\":\"table\",\"metric\":{\"type\":\"table_row_count\",\"name\":\"表行数\"}}", + "timeout": 60000, + "timeoutStrategy": "WARN", + "retryTimes": 3, + "retryInterval": 1000, + "preSql": "DELETE FROM temp_table", + "postSql": "INSERT INTO report_table SELECT * FROM result_table", + "errorDataStorageId": 1, + "runningNow": 1, + "createTime": "2023-01-01T00:00:00", + "updateTime": "2023-01-01T00:00:00" + } +} +``` + +### 示例代码 + +#### curl命令示例 +```bash +# 创建作业 +curl -X POST 'http://localhost:5678/api/v1/job' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx' \ + -d '{ + "type": "quality", + "dataSourceId": 1, + "jobName": "用户表质量检测", + "parameter": "{\"metricType\":\"table\",\"metric\":{\"type\":\"table_row_count\",\"name\":\"表行数\"}}", + "timeout": 60000, + "timeoutStrategy": "WARN", + "retryTimes": 3, + "retryInterval": 1000, + "preSql": "DELETE FROM temp_table", + "postSql": "INSERT INTO report_table SELECT * FROM result_table", + "errorDataStorageId": 1, + "runningNow": 1 +}' + +# 更新作业 +curl -X PUT 'http://localhost:5678/api/v1/job' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx' \ + -d '{ + "id": 123, + "type": "quality", + "dataSourceId": 1, + "jobName": "更新后的作业名称", + "parameter": "{\"metricType\":\"table\",\"metric\":{\"type\":\"table_row_count\",\"name\":\"表行数\"}}" +}' + +# 删除作业 +curl -X DELETE 'http://localhost:5678/api/v1/job/123' \ + -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx' + +# 获取作业详情 +curl -X GET 'http://localhost:5678/api/v1/job/123' \ + -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx' +``` + +#### Postman配置示例 +1. 打开Postman,创建新的请求 +2. 设置请求方法为POST +3. 输入URL:http://localhost:5678/api/v1/job +4. 在Headers标签页中添加: + - Key: Content-Type, Value: application/json + - Key: Authorization, Value: Bearer {access_token} +5. 在Body标签页中选择raw,然后选择JSON格式 +6. 输入请求体内容 +7. 点击Send按钮发送请求 + +**Section sources** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L45-L110) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java#L1-L79) +- [JobUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobUpdate.java#L1-L32) + +## 权限验证与访问控制 + +系统的权限验证和访问控制机制确保了数据安全和操作合规性。所有API请求都需要通过身份验证和权限检查,防止未授权访问和操作。 + +### 身份验证机制 + +系统采用基于JWT(JSON Web Token)的令牌认证机制。用户首先需要通过用户名和密码获取访问令牌,然后在后续的API请求中使用该令牌进行身份验证。 + +#### 获取访问令牌 +```bash +curl -X POST 'http://localhost:5678/api/v1/token' \ + -H 'Content-Type: application/json' \ + -d '{ + "userId": 1, + "workspaceId": 1, + "expireTime": "2023-12-31 23:59:59" +}' +``` + +响应示例: +```json +{ + "code": 0, + "message": "success", + "data": "eyJhbGciOiJIUzI1NiJ9.xxxxx" +} +``` + +#### 令牌验证流程 +1. 客户端在请求头中添加Authorization字段,值为"Bearer {token}" +2. 服务器接收到请求后,提取令牌并进行验证 +3. 验证令牌的有效性、过期时间和签名 +4. 如果验证通过,继续处理请求;否则返回401 Unauthorized错误 + +### 访问控制策略 + +系统实现了基于角色的访问控制(RBAC),不同角色的用户拥有不同的操作权限: + +- **管理员**:可以创建、读取、更新和删除所有作业 +- **开发者**:可以创建、读取和更新自己创建的作业 +- **查看者**:只能读取作业信息,不能进行修改操作 + +权限检查在API网关层和业务逻辑层双重进行,确保安全性。每个API端点都有明确的权限要求,系统会根据用户角色和资源所有权进行访问控制决策。 + +### 安全最佳实践 + +1. **令牌管理**:定期轮换访问令牌,设置合理的过期时间 +2. **最小权限原则**:为每个用户分配完成工作所需的最小权限 +3. **审计日志**:记录所有敏感操作,便于追踪和审计 +4. **HTTPS传输**:所有API通信都应通过HTTPS加密传输 +5. **输入验证**:对所有API输入进行严格的验证和过滤 + +**Section sources** +- [AccessTokenController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/AccessTokenController.java#L43-L62) +- [RefreshToken.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshToken.java#L1-L27) + +## 配置方式对比与选择建议 + +### Web界面配置 vs API配置 + +| 特性 | Web界面配置 | API配置 | +|------|-----------|--------| +| **易用性** | 高,图形化界面,操作直观 | 中,需要编写代码或脚本 | +| **学习曲线** | 低,适合非技术人员 | 高,需要编程知识 | +| **自动化能力** | 有限,主要依赖手动操作 | 高,可集成到自动化流程 | +| **批量操作** | 不支持 | 支持,可通过脚本批量创建 | +| **错误处理** | 友好的错误提示和引导 | 需要自行处理HTTP状态码 | +| **调试便利性** | 高,实时预览和测试 | 中,需要查看日志和响应 | +| **集成能力** | 有限 | 高,可与其他系统集成 | + +### 适用场景 + +**Web界面配置适用场景:** +- 日常运维和管理 +- 临时性或一次性作业创建 +- 非技术人员使用 +- 需要可视化预览和调试的场景 +- 小规模作业管理 + +**API配置适用场景:** +- CI/CD流程集成 +- 批量创建和管理作业 +- 自动化数据质量管理 +- 与其他系统(如监控系统、调度系统)集成 +- 大规模作业管理 +- 需要版本控制和代码审查的场景 + +### 选择建议 + +1. **团队规模和技能水平**:如果团队成员主要是业务分析师或数据工程师,建议使用Web界面配置;如果团队有较强的开发能力,可以考虑API配置。 + +2. **作业规模**:对于少量、固定的作业,Web界面配置更为便捷;对于大量、动态变化的作业,API配置更具优势。 + +3. **自动化需求**:如果需要将数据质量管理集成到自动化流程中,API配置是更好的选择。 + +4. **安全要求**:API配置可以更好地与现有的安全体系集成,如CI/CD中的密钥管理、访问控制等。 + +5. **维护成本**:Web界面配置的维护成本较低,适合快速迭代;API配置虽然初期投入较大,但长期来看更易于维护和扩展。 + +**Section sources** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L45-L110) +- [JobsList.tsx](file://datavines-ui/src/view/Main/HomeDetail/Jobs/JobsList.tsx#L1-L200) + +## 总结 + +本文档详细介绍了数据画像采集的两种配置方式:Web界面配置和API配置。Web界面配置提供了直观、易用的图形化操作界面,适合日常运维和非技术人员使用;API配置则提供了灵活、可编程的接口,适合自动化集成和大规模作业管理。 + +两种配置方式各有优势,用户应根据实际需求和团队能力选择合适的配置方法。对于大多数场景,建议结合使用两种方式:使用Web界面进行日常管理和调试,使用API进行自动化集成和批量操作。 + +系统的权限验证和访问控制机制确保了数据安全和操作合规性。通过基于JWT的令牌认证和基于角色的访问控制,系统能够有效防止未授权访问和操作。 + +未来,系统可以进一步优化配置体验,如提供配置模板、增强API文档、支持更多编程语言的SDK等,以满足不同用户的需求。 + +**Section sources** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L1-L111) +- [JobsList.tsx](file://datavines-ui/src/view/Main/HomeDetail/Jobs/JobsList.tsx#L1-L437) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\351\207\207\351\233\206\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\351\207\207\351\233\206\351\205\215\347\275\256.md" new file mode 100644 index 00000000..18d5e54b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\224\273\345\203\217/\351\207\207\351\233\206\351\205\215\347\275\256/\351\207\207\351\233\206\351\205\215\347\275\256.md" @@ -0,0 +1,404 @@ +# 采集配置 + + +**本文档引用的文件** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [SourceConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SourceConfig.java) +- [SinkConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SinkConfig.java) +- [TransformConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/TransformConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) +- [BaseConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/BaseConfig.java) +- [ConfigChecker.java](file://datavines-common/src/main/java/io/datavines/common/config/ConfigChecker.java) +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [submit_job_file_source.json](file://datavines-runner/src/main/resources/submit_job_file_source.json) +- [submit_job_mysql_storage.json](file://datavines-runner/src/main/resources/submit_job_mysql_storage.json) +- [config.ts](file://datavines-ui/src/type/config.ts) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细说明了如何配置和启动数据画像采集任务。文档涵盖了通过Web界面和API两种方式配置画像任务的步骤,解释了配置参数的含义,包括采集频率、采样率、目标表选择等。同时说明了如何设置增量采集和全量采集模式,提供了配置文件的结构和示例,包括JSON格式的配置模板。文档还解释了配置验证机制和错误处理,并涵盖了不同执行引擎(Spark、Flink、Local)的特定配置要求,最后提供了最佳实践建议。 + +## 项目结构 +数据画像采集系统采用模块化设计,主要包含以下几个核心模块:公共配置模块、连接器模块、引擎模块、度量模块、通知模块和服务器模块。系统通过配置驱动的方式实现数据采集任务的灵活配置和执行。 + +```mermaid +graph TB +subgraph "核心模块" +Common["datavines-common
公共配置和实体"] +Connector["datavines-connector
数据源连接器"] +Engine["datavines-engine
执行引擎"] +Metric["datavines-metric
度量指标"] +Notification["datavines-notification
通知服务"] +Server["datavines-server
服务器端"] +end +Common --> Engine +Common --> Connector +Common --> Server +Connector --> Engine +Engine --> Metric +Engine --> Notification +Server --> Engine +subgraph "工具和脚本" +Bin["bin/
启动脚本"] +Runner["datavines-runner
任务运行器"] +UI["datavines-ui
用户界面"] +end +Bin --> Server +Runner --> Engine +UI --> Server +``` + +**图示来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [submit_job_file_source.json](file://datavines-runner/src/main/resources/submit_job_file_source.json) + +## 核心组件 + +数据画像采集系统的核心组件包括配置管理、数据源连接、执行引擎、度量计算和结果存储。系统通过统一的配置模型来描述采集任务,支持多种数据源和执行引擎,实现了配置与执行的解耦。 + +**组件来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [SourceConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SourceConfig.java) +- [SinkConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SinkConfig.java) + +## 架构概述 + +系统采用分层架构设计,从上到下分为用户界面层、服务层、引擎层和数据层。用户通过Web界面或API提交采集任务配置,服务器端接收配置并进行验证,然后将任务提交给相应的执行引擎进行处理,最终将结果存储到指定的目标系统中。 + +```mermaid +graph TD +subgraph "用户交互层" +Web["Web界面"] +API["API接口"] +end +subgraph "服务层" +Server["datavines-server
任务调度和管理"] +Registry["注册中心
ZooKeeper/MySQL"] +end +subgraph "执行引擎层" +Spark["Spark引擎"] +Flink["Flink引擎"] +Local["本地引擎"] +end +subgraph "数据层" +Source["数据源
MySQL/Hive/File等"] +Sink["结果存储
MySQL/File等"] +Notification["通知系统
邮件/钉钉等"] +end +Web --> Server +API --> Server +Server --> Spark +Server --> Flink +Server --> Local +Spark --> Source +Flink --> Source +Local --> Source +Spark --> Sink +Flink --> Sink +Local --> Sink +Spark --> Notification +Flink --> Notification +Local --> Notification +Server --> Registry +``` + +**图示来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) + +## 详细组件分析 + +### 配置模型分析 +系统采用基于JSON的配置模型来描述数据画像采集任务。配置模型包含任务名称、环境配置、数据源配置、转换配置和结果存储配置等主要部分。 + +#### 配置类关系图 +```mermaid +classDiagram +class DataVinesJobConfig { ++String name ++EnvConfig envConfig ++SourceConfig[] sourceParameters ++TransformConfig[] transformParameters ++SinkConfig[] sinkParameters ++validate() void +} +class EnvConfig { ++String engine ++String type ++Map~String,Object~ config ++validate() void +} +class SourceConfig { ++String plugin ++String type ++Map~String,Object~ config +} +class TransformConfig { ++String plugin ++String type ++Map~String,Object~ config +} +class SinkConfig { ++String plugin ++String type ++Map~String,Object~ config +} +class BaseConfig { ++String plugin ++String type ++Map~String,Object~ config ++validate() void +} +DataVinesJobConfig --> EnvConfig : "包含" +DataVinesJobConfig --> SourceConfig : "包含" +DataVinesJobConfig --> TransformConfig : "包含" +DataVinesJobConfig --> SinkConfig : "包含" +SourceConfig --|> BaseConfig : "继承" +TransformConfig --|> BaseConfig : "继承" +SinkConfig --|> BaseConfig : "继承" +``` + +**图示来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [BaseConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/BaseConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) + +### 配置参数说明 +数据画像采集任务的配置参数主要包括以下几个方面: + +#### 任务基本信息 +- **name**: 任务名称,用于标识和管理采集任务 +- **engine**: 执行引擎,支持Spark、Flink和Local等 +- **type**: 执行类型,支持批处理(batch)和流处理(stream) + +#### 数据源配置 +数据源配置通过SourceConfig类定义,包含以下主要参数: +- **plugin**: 连接器插件类型,如mysql、hive、file等 +- **type**: 数据源类型 +- **config**: 具体的连接参数,如数据库连接信息、文件路径等 + +#### 采集模式配置 +系统支持全量采集和增量采集两种模式: +- **全量采集**: 每次采集都读取数据源中的全部数据 +- **增量采集**: 只采集自上次采集以来新增或修改的数据,通常通过时间戳或自增ID来实现 + +#### 采集频率和采样率 +- **采集频率**: 通过调度系统配置,支持固定间隔、cron表达式等方式 +- **采样率**: 在配置中通过参数指定,用于控制采集数据的比例,适用于大数据量场景下的性能优化 + +**组件来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [SourceConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SourceConfig.java) + +### 配置文件结构和示例 +系统支持JSON格式的配置文件,以下是一个完整的配置示例: + +```json +{ + "name": "用户数据画像采集", + "env": { + "engine": "spark", + "type": "batch", + "config": { + "programType": "java", + "deployMode": "cluster", + "driverCores": 1, + "driverMemory": "2g", + "numExecutors": 2, + "executorCores": 2, + "executorMemory": "4g" + } + }, + "sources": [ + { + "plugin": "mysql", + "type": "database", + "config": { + "host": "localhost", + "port": "3306", + "database": "user_db", + "user": "root", + "password": "password", + "table": "user_info", + "where": "create_time >= '${start_time}' AND create_time < '${end_time}'" + } + } + ], + "transforms": [ + { + "plugin": "data_profile", + "type": "profile", + "config": { + "metrics": [ + "table_row_count", + "column_null", + "column_duplicate" + ], + "sampleRate": 0.1 + } + } + ], + "sinks": [ + { + "plugin": "mysql", + "type": "database", + "config": { + "host": "localhost", + "port": "3306", + "database": "data_quality", + "user": "root", + "password": "password", + "table": "profile_results" + } + } + ] +} +``` + +**组件来源** +- [submit_job_mysql_storage.json](file://datavines-runner/src/main/resources/submit_job_mysql_storage.json) +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) + +### 配置验证机制和错误处理 +系统提供了完善的配置验证机制,确保配置的正确性和完整性。 + +#### 配置验证流程 +```mermaid +flowchart TD +Start([开始配置验证]) --> CheckName["检查任务名称是否为空"] +CheckName --> NameValid{"名称有效?"} +NameValid --> |否| ReturnError1["返回错误: 任务名称不能为空"] +NameValid --> |是| CheckEnv["检查环境配置"] +CheckEnv --> EnvValid{"环境配置有效?"} +EnvValid --> |否| ReturnError2["返回错误: 环境配置不完整"] +EnvValid --> |是| CheckSource["检查数据源配置"] +CheckSource --> SourceValid{"数据源配置有效?"} +SourceValid --> |否| ReturnError3["返回错误: 数据源配置不完整"] +SourceValid --> |是| CheckTransform["检查转换配置"] +CheckTransform --> TransformValid{"转换配置有效?"} +TransformValid --> |否| ReturnError4["返回错误: 转换配置不完整"] +TransformValid --> |是| CheckSink["检查结果存储配置"] +CheckSink --> SinkValid{"结果存储配置有效?"} +SinkValid --> |否| ReturnError5["返回错误: 结果存储配置不完整"] +SinkValid --> |是| ReturnSuccess["返回成功: 配置验证通过"] +ReturnError1 --> End([结束]) +ReturnError2 --> End +ReturnError3 --> End +ReturnError4 --> End +ReturnError5 --> End +ReturnSuccess --> End +``` + +**图示来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [ConfigChecker.java](file://datavines-common/src/main/java/io/datavines/common/config/ConfigChecker.java) + +### 执行引擎特定配置 +不同执行引擎有不同的配置要求,系统提供了相应的配置支持。 + +#### Spark引擎配置 +Spark引擎配置通过SparkEngineParameter类定义,包含以下主要参数: +- **programType**: 程序类型,如Java、Scala、Python等 +- **deployMode**: 部署模式,支持client和cluster模式 +- **driverCores**: Driver核心数 +- **driverMemory**: Driver内存 +- **numExecutors**: Executor数量 +- **executorCores**: 每个Executor的核心数 +- **executorMemory**: 每个Executor的内存 +- **others**: 其他参数 + +```mermaid +classDiagram +class SparkEngineParameter { ++String programType ++String deployMode ++int driverCores ++String driverMemory ++int numExecutors ++int executorCores ++String executorMemory ++String others +} +``` + +**图示来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) + +#### Flink引擎配置 +Flink引擎支持多种部署模式: +- **local**: 本地模式,用于开发和测试 +- **yarn-session**: YARN会话模式 +- **yarn-per-job**: YARN每个作业模式 +- **yarn-application**: YARN应用模式 + +#### Local引擎配置 +Local引擎适用于小规模数据处理和开发测试,配置相对简单,主要关注内存和CPU资源限制。 + +**组件来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java) + +## 依赖分析 + +系统各组件之间的依赖关系如下图所示: + +```mermaid +graph TD +UI["Web界面/datavines-ui"] --> Server["服务器/datavines-server"] +API["API接口"] --> Server +Server --> Engine["执行引擎/datavines-engine"] +Engine --> Connector["连接器/datavines-connector"] +Engine --> Metric["度量/datavines-metric"] +Engine --> Notification["通知/datavines-notification"] +Connector --> Source["数据源"] +Engine --> Execution["执行环境"] +Execution --> Spark["Spark"] +Execution --> Flink["Flink"] +Execution --> Local["Local"] +Server --> Registry["注册中心"] +Registry --> ZooKeeper["ZooKeeper"] +Registry --> MySQL["MySQL"] +``` + +**图示来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) + +## 性能考虑 + +在配置数据画像采集任务时,需要考虑以下性能因素: + +1. **资源消耗控制**: 合理配置执行引擎的资源参数,避免资源浪费或不足 +2. **大规模表采集策略**: 对于大规模表,建议使用分片采集、增量采集等方式 +3. **采样率设置**: 在保证数据质量的前提下,适当降低采样率以提高采集效率 +4. **并行度配置**: 根据数据量和系统资源合理设置并行度 +5. **数据缓存**: 合理利用缓存机制减少重复计算 + +## 故障排除指南 + +当配置和执行数据画像采集任务时,可能遇到以下常见问题: + +1. **配置验证失败**: 检查必填参数是否完整,参数值是否符合要求 +2. **连接失败**: 检查数据源连接信息是否正确,网络是否通畅 +3. **执行失败**: 检查执行引擎配置是否正确,资源是否充足 +4. **性能问题**: 检查资源配置是否合理,考虑优化采集策略 +5. **结果存储失败**: 检查目标存储系统是否可用,权限是否正确 + +**组件来源** +- [ConfigChecker.java](file://datavines-common/src/main/java/io/datavines/common/config/ConfigChecker.java) +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) + +## 结论 + +本文档详细介绍了数据画像采集系统的配置方法,包括配置模型、参数说明、配置文件结构、验证机制和执行引擎配置等。通过合理的配置,可以实现高效、可靠的数据画像采集任务。建议在实际使用中根据具体场景选择合适的配置策略,并遵循最佳实践来优化系统性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\205\203\346\225\260\346\215\256\345\220\214\346\255\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\205\203\346\225\260\346\215\256\345\220\214\346\255\245.md" new file mode 100644 index 00000000..eace5b12 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\205\203\346\225\260\346\215\256\345\220\214\346\255\245.md" @@ -0,0 +1,220 @@ +# 元数据同步 + + +**本文档引用的文件** +- [CatalogMetaDataFetchExecutor.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutor.java) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [CommonTaskContext.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskContext.java) +- [CommonTaskRequest.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskRequest.java) +- [CommonTaskResponse.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskResponse.java) +- [CommonTaskResponseQueue.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskResponseQueue.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) +- [FetchType.java](file://datavines-server/src/main/java/io/datavines/server/enums/FetchType.java) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [metadata.ts](file://datavines-ui/src/type/metadata.ts) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 简介 +本文档详细阐述了大数据平台中元数据同步功能的实现机制。该功能通过CatalogMetaDataFetchExecutor和CatalogMetaDataFetchTaskRunner两个核心组件实现,负责从各种数据源(如MySQL、PostgreSQL、Hive等)同步数据库、表和列的元数据信息。系统支持全量同步和增量同步两种模式,能够自动检测元数据变更(如新增、删除数据库/表/列,以及注释和类型变更),并记录这些变更。同步任务通过调度系统进行管理,支持并发执行,并提供了完善的监控和告警机制。 + +## 核心组件 +元数据同步功能的核心是`CatalogMetaDataFetchExecutor`接口及其具体实现`CatalogMetaDataFetchExecutorImpl`,以及负责执行任务的`CatalogMetaDataFetchTaskRunner`。`CatalogMetaDataFetchExecutorImpl`负责与数据源连接,获取元数据,并与数据库中已有的元数据进行对比,执行相应的增删改操作,并记录变更。`CatalogMetaDataFetchTaskRunner`则是一个可运行的任务,它创建`CatalogMetaDataFetchExecutorImpl`实例并执行同步操作,最后将执行结果通过响应队列上报。 + +**本文档引用的文件** +- [CatalogMetaDataFetchExecutor.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutor.java) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) + +## 架构概述 +元数据同步功能的架构遵循生产者-消费者模式。`CommonTaskScheduler`作为生产者,从命令队列中获取元数据同步命令,并将其转换为`CommonTask`对象,然后提交给`CommonTaskManager`。`CommonTaskManager`作为任务管理器,维护一个任务队列和一个固定大小的线程池。它将任务包装成`CommonTaskContext`并放入内部队列。`CommonTaskManager`内部的`TaskExecutor`线程不断从队列中取出任务,并根据任务类型创建相应的`TaskRunner`(如`CatalogMetaDataFetchTaskRunner`)并提交给线程池执行。任务执行完毕后,结果通过`CommonTaskResponseQueue`上报,由`TaskResponseOperator`线程处理,更新任务状态。 + +```mermaid +graph TD +subgraph "调度层" +CommonTaskScheduler["CommonTaskScheduler
生产者"] +end +subgraph "管理层" +CommonTaskManager["CommonTaskManager
任务管理器"] +TaskExecutor["TaskExecutor
任务分发"] +TaskResponseOperator["TaskResponseOperator
结果处理"] +end +subgraph "执行层" +CatalogMetaDataFetchTaskRunner["CatalogMetaDataFetchTaskRunner
任务执行器"] +CatalogMetaDataFetchExecutorImpl["CatalogMetaDataFetchExecutorImpl
执行逻辑"] +end +subgraph "数据源" +DataSource["外部数据源
(MySQL, Hive等)"] +end +subgraph "存储层" +Database["元数据存储数据库"] +end +CommonTaskScheduler --> |提交任务| CommonTaskManager +CommonTaskManager --> |分发任务| TaskExecutor +TaskExecutor --> |执行| CatalogMetaDataFetchTaskRunner +CatalogMetaDataFetchTaskRunner --> |调用| CatalogMetaDataFetchExecutorImpl +CatalogMetaDataFetchExecutorImpl --> |读取| DataSource +CatalogMetaDataFetchExecutorImpl --> |读写| Database +CatalogMetaDataFetchExecutorImpl --> |上报结果| CommonTaskManager +CommonTaskManager --> |处理结果| TaskResponseOperator +TaskResponseOperator --> |更新状态| Database +style CommonTaskScheduler fill:#f9f,stroke:#333 +style CommonTaskManager fill:#f9f,stroke:#333 +style TaskExecutor fill:#f9f,stroke:#333 +style TaskResponseOperator fill:#f9f,stroke:#333 +style CatalogMetaDataFetchTaskRunner fill:#bbf,stroke:#333 +style CatalogMetaDataFetchExecutorImpl fill:#bbf,stroke:#333 +style DataSource fill:#9f9,stroke:#333 +style Database fill:#9f9,stroke:#333 +``` + +**图表来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) + +## 详细组件分析 + +### CatalogMetaDataFetchExecutorImpl 分析 +`CatalogMetaDataFetchExecutorImpl`是元数据同步的核心执行逻辑。它实现了`CatalogMetaDataFetchExecutor`接口,其`execute()`方法根据请求的`fetchType`(数据源、数据库、表)执行不同的同步流程。 + +#### 全量与增量同步策略 +系统通过对比数据源当前的元数据与数据库中已存储的元数据来实现增量同步。以同步数据库为例: +1. **获取数据源元数据**:通过`ConnectorFactory`获取对应数据源类型的`Connector`,调用`getDatabases()`方法获取所有数据库列表。 +2. **获取数据库元数据**:从`CatalogEntityInstance`和`CatalogEntityRel`表中查询与该数据源关联的所有数据库实例。 +3. **对比与操作**: + * **新增**:存在于数据源但不存在于数据库中的数据库,会被创建,并记录`DATABASE_ADDED`变更。 + * **删除**:存在于数据库但不存在于数据源中的数据库,会被软删除,并记录`DATABASE_DELETED`变更。 + * **更新**:对于已存在的数据库,会进一步同步其下的表和列,并检测注释等属性的变化。 + +```mermaid +flowchart TD +Start([开始]) --> FetchType{"获取 fetchType"} +FetchType --> |DATASOURCE| FetchDataSource["执行 executeFetchDataSource()"] +FetchType --> |DATABASE| FetchDatabase["执行 executeFetchDatabase(database)"] +FetchType --> |TABLE| FetchTable["执行 executeFetchTable(database, table)"] +FetchDataSource --> End +FetchDatabase --> End +FetchTable --> End +style Start fill:#f96,stroke:#333 +style End fill:#f96,stroke:#333 +``` + +**图表来源** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L91-L105) + +#### 数据转换与映射规则 +从数据源获取的元数据(如`DatabaseInfo`, `TableInfo`, `ColumnInfo`)需要转换为平台内部的`CatalogEntityInstance`对象进行存储。主要映射规则如下: +* **类型映射**:`DatabaseInfo` -> `CatalogEntityInstance` (type="database"), `TableInfo` -> `CatalogEntityInstance` (type="table"), `ColumnInfo` -> `CatalogEntityInstance` (type="column")。 +* **属性映射**:`name` -> `displayName` 和 `fullyQualifiedName`,`comment` -> `description`,其他详细信息(如owner, createTime等)序列化为JSON字符串存储在`properties`字段中。 +* **关系映射**:通过`CatalogEntityRel`表建立父子关系,例如数据源与数据库、数据库与表、表与列。 + +#### 同步冲突处理与数据一致性 +* **幂等性**:系统的增删改操作设计为幂等的。例如,创建实体时会先检查是否已存在;更新时会基于UUID进行。 +* **软删除**:删除操作采用软删除(更新状态),而非物理删除,保证了数据的可追溯性。 +* **变更记录**:所有结构性变更(增、删、改注释、改类型)都会被记录在`CatalogSchemaChange`表中,确保了数据变更的可审计性。 +* **事务**:虽然代码中未显式展示,但`CatalogEntityInstanceService`和`CatalogEntityRelService`的`save`和`updateById`方法通常会在数据库事务中执行,保证了单个操作的原子性。 + +**本文档引用的文件** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) + +### CatalogMetaDataFetchTaskRunner 分析 +`CatalogMetaDataFetchTaskRunner`实现了`Runnable`接口,是实际在工作线程中执行的单元。它接收一个`CommonTaskContext`,从中获取任务请求,创建`CatalogMetaDataFetchExecutorImpl`实例并调用其`execute()`方法。执行成功或失败后,它会创建一个`CommonTaskResponse`对象,并将其放入`CommonTaskResponseQueue`中,以便`TaskResponseOperator`后续处理。 + +```mermaid +sequenceDiagram +participant TaskManager as CommonTaskManager +participant TaskRunner as CatalogMetaDataFetchTaskRunner +participant Executor as CatalogMetaDataFetchExecutorImpl +participant ResponseQueue as CommonTaskResponseQueue +TaskManager->>TaskRunner : run() +TaskRunner->>Executor : new CatalogMetaDataFetchExecutorImpl(request) +TaskRunner->>Executor : execute() +alt 执行成功 +Executor-->>TaskRunner : 成功 +TaskRunner->>ResponseQueue : add(SUCCESS Response) +else 执行失败 +Executor--x TaskRunner : 抛出异常 +TaskRunner->>ResponseQueue : add(FAILURE Response) +end +``` + +**图表来源** +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [CommonTaskResponseQueue.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskResponseQueue.java) + +## 依赖分析 +元数据同步功能依赖于多个核心模块: +* **Connector模块**:通过`ConnectorFactory` SPI机制,动态加载不同数据源(JDBC、Hive等)的连接器,用于获取元数据。 +* **Repository模块**:提供对`CatalogEntityInstance`、`CatalogEntityRel`、`CatalogSchemaChange`等实体的CRUD操作。 +* **Spring Context**:使用`SpringApplicationContext`的静态方法获取Spring容器中的Bean(如Service、ResponseQueue),实现依赖注入。 +* **Common模块**:提供通用的工具类(如`JSONUtils`、`StringUtils`)和配置项。 + +```mermaid +graph TD +CatalogMetaDataFetchExecutorImpl --> ConnectorFactory["ConnectorFactory
(datavines-connector-api)"] +CatalogMetaDataFetchExecutorImpl --> CatalogEntityInstanceService["CatalogEntityInstanceService
(datavines-server)"] +CatalogMetaDataFetchExecutorImpl --> CatalogEntityRelService["CatalogEntityRelService
(datavines-server)"] +CatalogMetaDataFetchExecutorImpl --> CatalogSchemaChangeService["CatalogSchemaChangeService
(datavines-server)"] +CatalogMetaDataFetchExecutorImpl --> SpringApplicationContext["SpringApplicationContext
(datavines-server)"] +CatalogMetaDataFetchExecutorImpl --> JSONUtils["JSONUtils
(datavines-common)"] +CatalogMetaDataFetchExecutorImpl --> StringUtils["StringUtils
(datavines-common)"] +style ConnectorFactory fill:#cfc +style CatalogEntityInstanceService fill:#cfc +style CatalogEntityRelService fill:#cfc +style CatalogSchemaChangeService fill:#cfc +style SpringApplicationContext fill:#cfc +style JSONUtils fill:#cfc +style StringUtils fill:#cfc +``` + +**图表来源** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) + +## 性能考虑 +系统在设计上考虑了性能和资源控制: +* **并发控制**:`CommonTaskManager`使用`Executors.newFixedThreadPool()`创建了一个固定大小的线程池,其大小由配置项`metadata.fetch.exec.threads`决定(默认值为5)。这可以防止创建过多线程导致系统资源耗尽。 +* **批量处理**:虽然单个任务是原子的,但系统通过调度器批量拉取和提交任务,提高了整体吞吐量。 +* **资源检查**:`CommonTaskScheduler`在每次循环中会调用`OSUtils.checkResource()`检查CPU负载和内存使用率,如果超过阈值(由`max.cpu.load.avg`和`reserved.memory`配置),则会暂停调度,避免在系统繁忙时加重负担。 +* **配置化**:关键性能参数(如线程数、资源阈值)均通过配置文件(`application.yaml`)或配置中心管理,便于调整。 + +**本文档引用的文件** +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java#L53-L57) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 故障排除指南 +### 任务状态查询 +任务状态通过`CommonTask`表进行管理。前端UI通过`metadata.ts`中定义的`TMetaDataFetchTaskTableItem`模型展示任务列表,包含`id`, `type`, `status` (submitted, running, failure, success, kill), `startTime`, `endTime`等字段。后端API(如`CatalogController`)提供接口供前端查询任务状态。 + +**本文档引用的文件** +- [metadata.ts](file://datavines-ui/src/type/metadata.ts) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) + +### 常见问题处理 +* **同步失败**:检查`CatalogMetaDataFetchTaskRunner`的日志,通常会记录具体的异常信息。常见原因包括数据源连接失败、权限不足、SQL语法错误等。确保数据源配置正确且网络可达。 +* **数据丢失**:由于系统采用软删除和变更记录,理论上不会发生数据丢失。如果发现元数据不一致,可通过查询`CatalogSchemaChange`表来追溯历史变更。 +* **任务卡住**:检查`CommonTask`表中任务的`status`和`executeHost`。如果任务长时间处于`running`状态,可能是执行节点宕机。系统通过`CommonTaskFailover`机制,当检测到节点失效时,会将分配给该节点的未完成任务重新分配给其他可用节点,实现故障转移。 + +**本文档引用的文件** +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java#L46-L49) +- [CommonTaskFailover.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskFailover.java) + +## 结论 +Datavines平台的元数据同步功能设计精巧,通过`CatalogMetaDataFetchExecutor`和`CatalogMetaDataFetchTaskRunner`的分工协作,实现了高效、可靠的元数据采集。系统支持灵活的全量/增量同步策略,能够精确捕捉元数据变更,并通过变更记录保障了数据一致性。其基于生产者-消费者模式的架构和可配置的并发控制,确保了系统的稳定性和可扩展性。完善的监控和故障转移机制进一步提升了系统的健壮性,为数据治理提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\205\203\346\225\260\346\215\256\346\237\245\350\257\242.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\205\203\346\225\260\346\215\256\346\237\245\350\257\242.md" new file mode 100644 index 00000000..27002a81 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\205\203\346\225\260\346\215\256\346\237\245\350\257\242.md" @@ -0,0 +1,298 @@ +# 元数据查询 + + +**本文档引用的文件** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java) +- [CatalogTableDetailVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogTableDetailVO.java) +- [CatalogColumnDetailVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogColumnDetailVO.java) +- [CatalogDatabaseDetailVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogDatabaseDetailVO.java) +- [CatalogEntityMetricParameter.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogEntityMetricParameter.java) + + +## 目录 +1. [简介](#简介) +2. [核心查询接口](#核心查询接口) +3. [查询参数与过滤条件](#查询参数与过滤条件) +4. [分页处理机制](#分页处理机制) +5. [高级查询功能](#高级查询功能) +6. [查询结果结构](#查询结果结构) +7. [性能优化策略](#性能优化策略) +8. [常见问题解决](#常见问题解决) + +## 简介 +元数据查询功能是DataVines系统的核心组件之一,通过CatalogController提供的REST API接口,用户可以按名称、标签、分类等条件检索数据库、表、列等元数据信息。该功能支持分页查询、模糊搜索和组合条件查询,为数据治理和质量监控提供了基础支持。 + +## 核心查询接口 + +CatalogController提供了丰富的元数据查询接口,主要分为以下几类: + +### 实体列表查询 +- `/catalog/list/database/{upstreamUuid}`: 根据上游UUID获取数据库列表 +- `/catalog/list/table/{upstreamUuid}`: 根据上游UUID获取表列表 +- `/catalog/list/column/{upstreamUuid}`: 根据上游UUID获取列列表 + +### 详细信息查询 +- `/catalog/detail/database/{uuid}`: 获取数据库实体详细信息 +- `/catalog/detail/table/{uuid}`: 获取表实体详细信息 +- `/catalog/detail/column/{uuid}`: 获取列实体详细信息 + +### 分页查询 +- `/catalog/page/table-with-detail`: 获取带详细信息的表分页数据 +- `/catalog/page/column-with-detail`: 获取带详细信息的列分页数据 +- `/catalog/page/entity/metric`: 获取实体指标分页数据 +- `/catalog/page/entity/issue`: 获取实体问题分页数据 + +### 其他查询 +- `/catalog/profile/table/{uuid}`: 获取表实体的分析概况 +- `/catalog/profile/column/{uuid}`: 获取列实体的分析概况 +- `/catalog/entity/metric/parameter/{uuid}`: 获取实体指标参数 + +**Section sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L110-L157) + +## 查询参数与过滤条件 + +### 基本查询参数 +所有分页查询接口都支持以下基本参数: +- `upstreamUuid`: 上游实体的唯一标识符,用于确定查询范围 +- `pageNumber`: 当前页码,从1开始 +- `pageSize`: 每页记录数 +- `name`: 名称过滤条件,支持模糊匹配 + +### 时间范围查询 +部分接口支持时间范围查询,如: +- `startTime`: 开始时间,格式为YYYY-MM-DD HH:MM:SS +- `endTime`: 结束时间,格式为YYYY-MM-DD HH:MM:SS + +当未提供时间范围时,系统默认使用最近7天的数据范围。 + +### 过滤条件实现 +在服务端实现中,查询条件通过MyBatis Plus的QueryWrapper构建: +```java +queryWrapper.lambda() + .in(CatalogEntityInstance::getUuid, uuidList) + .eq(CatalogEntityInstance::getStatus, CommonConstants.CATALOG_ENTITY_INSTANCE_STATUS_ACTIVE) + .and(StringUtils.isNotEmpty(name), qw -> qw.like(CatalogEntityInstance::getDisplayName, name) + .or() + .like(CatalogEntityInstance::getDescription, name)) +``` + +这种实现方式支持对显示名称和描述字段的模糊匹配,提高了查询的灵活性。 + +**Section sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L136-L141) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L166-L173) + +## 分页处理机制 + +### 分页接口设计 +系统采用标准的分页响应格式,包含以下字段: +- `records`: 当前页的数据记录列表 +- `total`: 总记录数 +- `size`: 每页大小 +- `current`: 当前页码 +- `pages`: 总页数 + +### 分页实现原理 +分页功能通过MyBatis Plus的Page对象实现: +```java +Page page = new Page<>(pageNumber, pageSize); +return page(page, queryWrapper); +``` + +服务端首先根据upstreamUuid获取所有子实体的UUID列表,然后基于这些UUID进行分页查询,确保查询结果的准确性和一致性。 + +### 前端分页集成 +前端通过Ant Design的Pagination组件实现分页交互: +```typescript + +``` + +这种设计提供了良好的用户体验,支持页码跳转、每页大小调整等功能。 + +**Section sources** +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L163-L174) +- [Card.tsx](file://datavines-ui/src/view/Main/Home/List/Card.tsx#L158-L164) + +## 高级查询功能 + +### 模糊搜索 +系统支持基于名称的模糊搜索功能,用户可以在查询时输入部分名称进行匹配。实现方式是使用SQL的LIKE操作符: +```java +.like(CatalogEntityInstance::getDisplayName, name) +.or() +.like(CatalogEntityInstance::getDescription, name) +``` + +这种设计允许用户通过显示名称或描述字段的部分内容找到目标实体。 + +### 组合条件查询 +虽然当前接口主要支持基于名称的单一条件查询,但通过服务端的QueryWrapper构建机制,系统具备扩展组合条件查询的能力。未来可以轻松添加基于标签、分类、创建时间等更多维度的查询条件。 + +### 数据分析查询 +系统提供了专门的数据分析查询接口: +- `/catalog/profile/table/{uuid}`: 获取表的分析概况 +- `/catalog/profile/column/{uuid}`: 获取列的分析概况 +- `/catalog/profile/execute`: 执行数据概况分析作业 + +这些接口为数据质量分析和监控提供了重要支持。 + +**Section sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L136-L141) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L166-L173) + +## 查询结果结构 + +### 基础结构 +所有查询结果都遵循统一的响应格式,包含标准的API响应字段: +- `code`: 响应状态码 +- `message`: 响应消息 +- `data`: 实际数据内容 + +### 实体详细信息结构 +#### 数据库详细信息 (CatalogDatabaseDetailVO) +- `name`: 数据库名称 +- `type`: 实体类型 +- `uuid`: 唯一标识符 +- `updateTime`: 更新时间 +- `tables`: 表数量 +- `metrics`: 指标数量 +- `tags`: 标签数量 + +#### 表详细信息 (CatalogTableDetailVO) +- `name`: 表名称 +- `type`: 实体类型 +- `uuid`: 唯一标识符 +- `updateTime`: 更新时间 +- `comment`: 注释 +- `columns`: 列数量 +- `records`: 记录数 +- `metrics`: 指标数量 +- `tags`: 标签数量 + +#### 列详细信息 (CatalogColumnDetailVO) +- `name`: 列名称 +- `type`: 实体类型 +- `uuid`: 唯一标识符 +- `updateTime`: 更新时间 +- `comment`: 注释 +- `dataType`: 数据类型 +- `metrics`: 指标数量 +- `tags`: 标签数量 + +### 指标参数结构 +`CatalogEntityMetricParameter`类定义了指标查询所需的参数: +- `dataSourceId`: 数据源ID +- `database`: 数据库名称 +- `table`: 表名称 +- `column`: 列名称 + +这些结构通过Lombok的@Data注解自动生成getter、setter、toString等方法,简化了代码维护。 + +**Section sources** +- [CatalogDatabaseDetailVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogDatabaseDetailVO.java#L21-L26) +- [CatalogTableDetailVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogTableDetailVO.java#L21-L31) +- [CatalogColumnDetailVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogColumnDetailVO.java#L21-L26) +- [CatalogEntityMetricParameter.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogEntityMetricParameter.java#L21-L31) + +## 性能优化策略 + +### 索引使用 +系统在关键字段上建立了数据库索引,包括: +- `uuid`: 实体唯一标识符索引 +- `displayName`: 显示名称索引,支持模糊查询 +- `status`: 状态字段索引,用于快速过滤活跃实体 +- `upstreamUuid`: 上游UUID索引,用于快速查找子实体 + +### 查询优化 +#### 批量查询优化 +系统采用批量查询策略,先获取所有相关实体的UUID列表,然后进行批量查询: +```java +List uuidList = new ArrayList<>(); +entityRelList.forEach(x->{ + uuidList.add(x.getEntity2Uuid()); +}); +``` + +这种方式减少了数据库查询次数,提高了查询效率。 + +#### 缓存机制 +虽然当前代码中未直接体现,但基于Spring框架的特性,系统可以通过添加@Cacheable注解实现查询结果缓存,减少对数据库的重复查询。 + +### 分页优化 +系统实现了智能分页策略: +- 当查询结果为空时,直接返回null,避免不必要的处理 +- 使用MyBatis Plus的分页插件,生成优化的SQL语句 +- 支持大结果集的流式处理,避免内存溢出 + +### 前端优化 +前端通过以下方式优化查询性能: +- 防抖搜索:在用户输入时添加防抖,避免频繁请求 +- 懒加载:只在需要时加载数据,减少初始加载时间 +- 数据缓存:在客户端缓存已查询的数据,减少重复请求 + +**Section sources** +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L156-L173) + +## 常见问题解决 + +### 查询超时 +**问题原因**: +- 数据量过大导致查询时间过长 +- 数据库索引缺失或不合理 +- 网络延迟较高 + +**解决方案**: +1. 优化查询条件,使用更精确的过滤条件 +2. 检查并优化数据库索引 +3. 调整分页大小,避免一次性查询过多数据 +4. 增加查询超时时间配置 + +### 结果不准确 +**问题原因**: +- 元数据未及时更新 +- 查询条件理解错误 +- 数据同步延迟 + +**解决方案**: +1. 手动触发元数据刷新:`/catalog/refresh` +2. 检查数据源连接状态 +3. 验证查询参数的正确性 +4. 查看元数据抓取任务的执行日志 + +### 空结果返回 +**问题原因**: +- 查询条件过于严格 +- 数据源中确实不存在匹配的数据 +- 权限不足,无法访问目标数据 + +**解决方案**: +1. 放宽查询条件,如减少模糊匹配的精确度 +2. 验证数据源中是否存在目标数据 +3. 检查用户权限配置 +4. 查看系统日志,确认是否有错误信息 + +### 性能问题 +**问题表现**: +- 查询响应时间过长 +- 系统资源占用过高 +- 并发查询时性能下降明显 + +**优化建议**: +1. 添加适当的数据库索引 +2. 优化查询SQL,避免全表扫描 +3. 实现查询结果缓存 +4. 调整JVM参数,优化内存使用 +5. 考虑读写分离,将查询请求分发到只读副本 + +**Section sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L69-L73) +- [Status.java](file://datavines-core/src/main/java/io/datavines/core/enums/Status.java#L120-L120) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206.md" new file mode 100644 index 00000000..d3a8049f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206.md" @@ -0,0 +1,316 @@ +# 元数据管理 + + +**本文档引用的文件** +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java) +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) +- [metadata.ts](file://datavines-ui/src/type/metadata.ts) +- [Card.tsx](file://datavines-ui/src/view/Main/Home/List/Card.tsx) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + + +## 目录 +1. [引言](#引言) +2. [核心实体结构](#核心实体结构) +3. [元数据采集机制](#元数据采集机制) +4. [元数据生命周期管理](#元数据生命周期管理) +5. [元数据查询功能](#元数据查询功能) +6. [版本控制与变更历史](#版本控制与变更历史) +7. [元数据质量评估](#元数据质量评估) +8. [常见问题与解决方案](#常见问题与解决方案) +9. [结论](#结论) + +## 引言 + +DataVines 是一个数据质量与元数据管理平台,其元数据管理功能是整个系统的核心组成部分。该功能旨在提供全面的数据资产管理能力,包括元数据的采集、存储、查询和生命周期管理。通过元数据管理,用户可以清晰地了解数据资产的结构、关系和使用情况,从而提高数据的可发现性、可理解性和可信度。本文档将详细阐述DataVines中元数据管理的各项功能,包括CatalogEntityDefinition和CatalogEntityInstance实体的结构与关系,元数据的采集、存储、查询、版本控制和质量评估机制。 + +**Section sources** +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java#L1-L79) +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java#L1-L64) + +## 核心实体结构 + +DataVines的元数据管理基于两个核心实体:`CatalogEntityDefinition`(元数据实体定义)和`CatalogEntityInstance`(元数据实体实例)。这两个实体共同构成了元数据的模型基础。 + +### CatalogEntityDefinition 实体 + +`CatalogEntityDefinition` 实体用于定义元数据实体的类型和通用属性。它相当于一个元数据模板,描述了某一类数据资产(如数据库、表、列)的通用特征。 + +该实体的主要属性包括: +- **uuid**: 实体定义的唯一标识符 +- **name**: 实体类型的名称(如"database"、"table"、"column") +- **description**: 对实体类型的描述 +- **properties**: 以JSON格式存储的其他扩展属性 +- **superUuid**: 指向父级实体定义的UUID,用于构建实体定义的继承关系 + +### CatalogEntityInstance 实体 + +`CatalogEntityInstance` 实体是`CatalogEntityDefinition`的具体实例,代表了实际存在的数据资产。例如,一个名为"sales_db"的数据库或一个名为"orders"的表都是`CatalogEntityInstance`的实例。 + +该实体的主要属性包括: +- **id**: 数据库主键 +- **uuid**: 实体实例的唯一标识符 +- **type**: 实体类型,对应`CatalogEntityDefinition`的名称 +- **datasourceId**: 关联的数据源ID +- **fullyQualifiedName**: 全限定名,用于唯一标识该实体 +- **displayName**: 展示名称 +- **description**: 实体描述 +- **properties**: 以JSON格式存储的实体特定属性 +- **owner**: 实体所有者 +- **version**: 实体版本号 +- **status**: 实体状态(active表示启用,deleted开头的随机数表示已删除) +- **createTime**: 创建时间 +- **updateTime**: 更新时间 +- **updateBy**: 更新用户ID + +这两个实体通过`type`字段建立关联,`CatalogEntityInstance`的`type`值引用`CatalogEntityDefinition`的`name`值。这种设计实现了元数据模型的灵活性和可扩展性。 + +```mermaid +erDiagram +CATALOG_ENTITY_DEFINITION { +string uuid PK +string name +string description +text properties +string super_uuid +timestamp create_time +timestamp update_time +} +CATALOG_ENTITY_INSTANCE { +bigint id PK +string uuid UK +string type FK +bigint datasource_id +string fully_qualified_name UK +string display_name +string description +text properties +string owner +string version +string status +timestamp create_time +timestamp update_time +bigint update_by +} +CATALOG_ENTITY_DEFINITION ||--o{ CATALOG_ENTITY_INSTANCE : "定义" +``` + +**Diagram sources ** +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java#L1-L64) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java#L1-L79) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L198-L233) + +**Section sources** +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java#L1-L64) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java#L1-L79) + +## 元数据采集机制 + +DataVines提供了两种元数据采集模式:手动录入和自动同步。自动同步是主要的采集方式,通过定时任务从各种数据源中提取元数据。 + +### 自动同步实现 + +元数据的自动同步由`CatalogMetaDataFetchTaskRunner`和`CatalogMetaDataFetchExecutorImpl`两个核心组件协同完成。`CatalogMetaDataFetchTaskRunner`实现了`Runnable`接口,作为任务执行器在独立线程中运行。它接收`CommonTaskContext`作为上下文,并通过`CommonTaskResponseQueue`上报任务执行结果。 + +```mermaid +sequenceDiagram +participant Scheduler as 调度器 +participant Runner as CatalogMetaDataFetchTaskRunner +participant Executor as CatalogMetaDataFetchExecutorImpl +participant Queue as CommonTaskResponseQueue +Scheduler->>Runner : 启动任务 (run) +Runner->>Executor : 创建执行器实例 +Runner->>Executor : execute() +alt 执行成功 +Executor-->>Runner : 成功 +Runner->>Queue : 添加成功响应 +else 执行失败 +Executor--x Runner : 异常 +Runner->>Queue : 添加失败响应 +end +``` + +**Diagram sources ** +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java#L26-L51) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) + +**Section sources** +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java#L26-L51) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) + +### 采集配置与触发 + +元数据采集任务的配置和触发主要通过前端界面和后端API实现。在UI层面,用户可以通过"数据源"列表中的"元数据采集"按钮(`FundOutlined`图标)来触发采集任务。后端通过`CatalogController`中的`refreshCatalog`接口接收采集请求,并通过`CommonTaskService`调度具体的采集任务。 + +系统还支持配置采集相关的参数,如`metadata.fetch.exec.threads`(元数据采集执行线程数,默认5个)和`CATALOG_METADATA_TASK_LOCK_KEY`(元数据采集任务锁的注册中心键),这些参数可以在`application.yaml`配置文件中进行调整。 + +**Section sources** +- [Card.tsx](file://datavines-ui/src/view/Main/Home/List/Card.tsx#L97-L105) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L69-L73) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java#L34-L54) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 元数据生命周期管理 + +DataVines提供了完整的元数据生命周期管理功能,包括创建、更新和删除操作,这些操作主要通过RESTful API接口实现。 + +### API接口与使用方法 + +`CatalogController`类定义了管理元数据生命周期的核心API接口: + +- **创建**: 通过`catalogEntityInstanceService.create()`方法创建新的元数据实体实例。该方法接收一个`CatalogEntityInstance`对象作为参数,并将其持久化到数据库中。 +- **更新**: 更新操作主要通过修改实体的`status`字段来实现。`CatalogEntityInstanceServiceImpl`中的`updateStatus`方法允许将实体状态从"active"更改为"deleted"前缀的状态,实现软删除。 +- **删除**: 系统提供了多种删除方法,包括`deleteEntityByUUID`(通过UUID删除)、`deleteEntityByDataSourceAndFQN`(通过数据源ID和全限定名删除)和`softDeleteEntityByDataSourceAndFQN`(软删除)。软删除通过更改状态而非物理删除数据来实现。 + +```mermaid +flowchart TD +Start([开始]) --> Create["创建元数据实体"] +Create --> Store["持久化到数据库"] +Store --> End1([创建完成]) +Start --> Update["更新元数据实体"] +Update --> Modify["修改实体属性"] +Modify --> CheckStatus{"状态变更?"} +CheckStatus --> |是| UpdateStatus["调用updateStatus()"] +CheckStatus --> |否| SaveChanges["保存其他修改"] +UpdateStatus --> End2([更新完成]) +SaveChanges --> End2 +Start --> Delete["删除元数据实体"] +Delete --> SoftDelete["软删除: updateStatus(deleted)"] +SoftDelete --> End3([删除完成]) +``` + +**Diagram sources ** +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L87-L90) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java#L41-L49) + +**Section sources** +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L87-L90) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java#L41-L49) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) + +## 元数据查询功能 + +DataVines提供了丰富的元数据查询功能,支持通过多种条件检索数据资产,包括实体类型、名称、标签等。 + +### 查询接口与示例 + +`CatalogController`提供了多个查询接口,支持分页和条件过滤: + +- **按层级查询**: 通过`getDatabaseList`、`getTableList`和`getColumnList`接口,可以按数据源->数据库->表->列的层级结构查询元数据。这些接口接收`upstreamUuid`参数,返回指定上级实体下的所有子实体。 +- **带详情查询**: `getCatalogTableWithDetailList`和`getCatalogColumnWithDetailList`接口返回包含详细信息的实体列表,而`getCatalogTableWithDetailPage`和`getCatalogColumnWithDetailPage`则支持分页查询。 +- **实体详情查询**: `getDatabaseEntityDetail`、`getTableEntityDetail`和`getColumnEntityDetail`接口返回指定UUID的实体完整详情。 + +查询示例: +```http +GET /api/v1/catalog/list/table/{database_uuid} +返回: [{uuid: "tbl-1", displayName: "users", type: "table"}, ...] + +GET /api/v1/catalog/page/table-with-detail?upstreamUuid={db_uuid}&name=order&pageNumber=1&pageSize=10 +返回: 分页的表详情列表 +``` + +**Section sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L110-L156) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java#L43-L57) +- [metadata.ts](file://datavines-ui/src/type/metadata.ts) + +## 版本控制与变更历史 + +DataVines通过`CatalogSchemaChange`实体实现了元数据的版本控制和变更历史记录功能,这对于追踪数据结构的演变至关重要。 + +### 变更历史记录 + +每当元数据实体(如表结构)发生变更时,系统会创建一条`CatalogSchemaChange`记录。该实体包含以下关键信息: +- **id**: 主键 +- **entityUuid**: 关联的元数据实体UUID +- **changeType**: 变更类型(如新增列、删除列、修改列类型等) +- **changeDetail**: 变更详情,以JSON格式存储具体的变更内容 +- **changeTime**: 变更发生的时间 +- **operator**: 操作者 + +用户可以通过`CatalogController`中的`getSchemaChangeList`和`getSchemaChangePage`接口查询特定实体的变更历史。这些接口返回按时间倒序排列的变更记录,使用户能够清晰地了解数据结构的演变过程。 + +```mermaid +classDiagram +class CatalogSchemaChange { ++Long id ++String entityUuid ++Integer changeType ++String changeDetail ++LocalDateTime changeTime ++String operator +} +class CatalogEntityInstance { ++String uuid ++String type ++String fullyQualifiedName ++String displayName ++String status +} +CatalogEntityInstance "1" *-- "0..*" CatalogSchemaChange : "拥有" +``` + +**Diagram sources ** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java) + +**Section sources** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L201-L213) + +## 元数据质量评估 + +元数据质量评估是DataVines的核心功能之一,它允许用户为数据资产定义和执行质量检查规则。 + +### 配置与指标 + +元数据质量评估主要通过`CatalogEntityInstanceService`的`entityAddMetric`方法实现。该方法接收`JobCreateWithEntityUuid`对象,将质量检查任务(metric job)与特定的元数据实体关联起来。 + +质量评估的配置包括: +- **指标类型**: 如完整性、一致性、有效性、时效性、唯一性、准确性等 +- **预期值**: 定义指标的预期结果 +- **过滤条件**: 指定评估数据的范围 +- **执行计划**: 定义任务的调度频率 + +用户可以通过`getEntityMetricList`接口查询与特定实体关联的所有质量评估任务,并通过`getEntityMetricParameter`接口获取任务的具体参数配置。 + +**Section sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L215-L225) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java#L69-L73) +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java) + +## 常见问题与解决方案 + +在使用DataVines元数据管理功能时,可能会遇到一些常见问题,以下是针对这些问题的解决方案。 + +### 元数据同步失败 + +**问题**: 元数据采集任务执行失败,状态显示为"failure"。 +**解决方案**: +1. 检查数据源连接是否正常,确保网络可达且认证信息正确。 +2. 查看系统日志,定位具体的错误信息。 +3. 检查`metadata.fetch.exec.threads`配置,确保有足够的线程资源。 +4. 确认数据源的元数据查询权限是否足够。 + +### 数据不一致 + +**问题**: UI显示的元数据与实际数据源不一致。 +**解决方案**: +1. 手动触发元数据采集任务,强制刷新元数据。 +2. 检查`CatalogEntityInstance`表中的`status`字段,确认是否有被软删除的实体。 +3. 验证`fully_qualified_name`的唯一性约束,避免因命名冲突导致的数据覆盖。 + +**Section sources** +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java#L46-L48) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java#L225) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L231) + +## 结论 + +DataVines的元数据管理功能提供了一个全面、灵活且可扩展的解决方案,用于管理现代数据环境中的数据资产。通过`CatalogEntityDefinition`和`CatalogEntityInstance`两个核心实体,系统实现了元数据模型的定义与实例化。自动化的元数据采集机制确保了数据目录的实时性和准确性。丰富的查询接口和分页支持使得大规模元数据的检索变得高效。版本控制和变更历史功能为数据治理提供了重要的审计能力。最后,与数据质量评估的深度集成,使得元数据不仅是描述性的信息,更成为主动管理数据健康度的基础。这些功能共同构成了一个强大的元数据管理平台,为数据驱动的决策提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\256\236\344\275\223\345\256\232\344\271\211.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\256\236\344\275\223\345\256\232\344\271\211.md" new file mode 100644 index 00000000..f7e372e5 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\256\236\344\275\223\345\256\232\344\271\211.md" @@ -0,0 +1,279 @@ +# 实体定义 + + +**本文档中引用的文件** +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) +- [CatalogEntityDefinitionMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityDefinitionMapper.java) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [StructField.java](file://datavines-connector/ datavines-connector-api/src/main/java/io/datavines/connector/api/entity/StructField.java) +- [CatalogEntityBaseDetailVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogEntityBaseDetailVO.java) +- [CatalogColumnDetailVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogColumnDetailVO.java) + + +## 目录 +1. [简介](#简介) +2. [实体定义结构](#实体定义结构) +3. [API操作](#api操作) +4. [验证规则与约束](#验证规则与约束) +5. [与数据源和表结构的映射关系](#与数据源和表结构的映射关系) +6. [版本管理与变更审计](#版本管理与变更审计) +7. [最佳实践](#最佳实践) +8. [常见问题解决](#常见问题解决) + +## 简介 +实体定义是DataVines系统中用于描述数据实体(如数据库、表、列等)元数据的核心组件。它提供了对数据资产的统一描述方式,支持数据目录、数据质量监控、数据血缘分析等功能。通过实体定义,用户可以对数据进行分类、标记、监控和分析。 + +**Section sources** +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java#L1-L64) + +## 实体定义结构 +`CatalogEntityDefinition`类定义了实体的基本属性,包括名称、描述、类型等。该类映射到数据库表`dv_catalog_entity_definition`,存储所有实体定义的元数据。 + +### 核心字段 +- **id**: 主键,自增 +- **uuid**: 实体唯一标识符 +- **name**: 实体名称 +- **description**: 实体描述 +- **properties**: 实体属性,以JSON格式存储 +- **superUuid**: 父实体UUID,用于建立实体层级关系 +- **createBy**: 创建者ID +- **createTime**: 创建时间 +- **updateBy**: 更新者ID +- **updateTime**: 更新时间 + +```mermaid +classDiagram +class CatalogEntityDefinition { ++Long id ++String uuid ++String name ++String description ++String properties ++String superUuid ++Long createBy ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +``` + +**Diagram sources** +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java#L26-L63) + +**Section sources** +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java#L26-L63) + +## API操作 +系统提供了RESTful API来管理实体定义的生命周期,包括创建、更新和删除操作。 + +### 创建实体定义 +通过POST请求创建新的实体定义。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "CatalogController" +participant Service as "CatalogEntityDefinitionService" +participant Mapper as "CatalogEntityDefinitionMapper" +participant DB as "数据库" +Client->>Controller : POST /api/catalog/entity +Controller->>Service : createEntityDefinition(request) +Service->>Mapper : insert(entityDefinition) +Mapper->>DB : INSERT INTO dv_catalog_entity_definition +DB-->>Mapper : 返回插入结果 +Mapper-->>Service : 操作结果 +Service-->>Controller : 创建成功 +Controller-->>Client : 返回实体UUID +``` + +**Diagram sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L70-L73) +- [CatalogEntityDefinitionMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityDefinitionMapper.java#L23-L26) + +### 更新实体定义 +通过PUT请求更新现有实体定义。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "CatalogController" +participant Service as "CatalogEntityDefinitionService" +participant Mapper as "CatalogEntityDefinitionMapper" +participant DB as "数据库" +Client->>Controller : PUT /api/catalog/entity/{uuid} +Controller->>Service : updateEntityDefinition(uuid, request) +Service->>Mapper : updateByUuid(uuid, entityDefinition) +Mapper->>DB : UPDATE dv_catalog_entity_definition +DB-->>Mapper : 返回更新结果 +Mapper-->>Service : 操作结果 +Service-->>Controller : 更新成功 +Controller-->>Client : 返回成功状态 +``` + +**Diagram sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L75-L82) +- [CatalogEntityDefinitionMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityDefinitionMapper.java#L23-L26) + +### 删除实体定义 +通过DELETE请求删除实体定义。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "CatalogController" +participant Service as "CatalogEntityDefinitionService" +participant Mapper as "CatalogEntityDefinitionMapper" +participant DB as "数据库" +Client->>Controller : DELETE /api/catalog/entity/{uuid} +Controller->>Service : deleteEntityDefinition(uuid) +Service->>Mapper : deleteByUuid(uuid) +Mapper->>DB : DELETE FROM dv_catalog_entity_definition +DB-->>Mapper : 返回删除结果 +Mapper-->>Service : 操作结果 +Service-->>Controller : 删除成功 +Controller-->>Client : 返回成功状态 +``` + +**Diagram sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L83-L90) +- [CatalogEntityDefinitionMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityDefinitionMapper.java#L23-L26) + +## 验证规则与约束 +实体定义遵循严格的验证规则,确保数据的一致性和完整性。 + +### 命名规范 +- 名称不能为空,长度限制为255个字符 +- UUID必须唯一,长度为64个字符 +- 名称和UUID不能包含特殊字符 + +### 必填字段 +- `uuid`: 必填,唯一标识 +- `name`: 必填,实体名称 +- `createBy`: 必填,创建者ID + +### 数据库约束 +```sql +CREATE TABLE `dv_catalog_entity_definition` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `uuid` varchar(64) NOT NULL COMMENT '实体定义UUID', + `name` varchar(255) NOT NULL COMMENT '实体定义的名字', + `description` varchar(255) DEFAULT NULL COMMENT '描述', + `properties` text COMMENT '实体参数', + `superUuid` varchar(64) DEFAULT NULL COMMENT '父实体UUID', + `create_by` bigint(20) NOT NULL COMMENT '创建者ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者ID', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_uuid` (`uuid`), + KEY `idx_name` (`name`), + KEY `idx_super_uuid` (`superUuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='实体定义表'; +``` + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L191-L200) +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java#L35-L39) + +## 与数据源和表结构的映射关系 +实体定义与数据源和表结构之间存在明确的映射关系,支持元数据的同步和管理。 + +### 映射模型 +```mermaid +erDiagram +dv_catalog_entity_definition ||--o{ dv_catalog_entity_instance : "包含" +dv_catalog_entity_definition ||--o{ dv_catalog_entity_profile : "生成" +dv_catalog_entity_definition ||--o{ dv_catalog_entity_metric_job_rel : "关联" +dv_catalog_entity_definition ||--o{ dv_catalog_entity_tag_rel : "标记" +dv_catalog_entity_definition { +bigint id PK +varchar uuid UK +varchar name +varchar description +text properties +varchar superUuid FK +bigint createBy +datetime createTime +bigint updateBy +datetime updateTime +} +dv_catalog_entity_instance { +bigint id PK +varchar entityUuid FK +varchar dataSourceUuid +varchar databaseName +varchar tableName +varchar columnName +datetime createTime +datetime updateTime +} +``` + +**Diagram sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L191-L200) +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java) + +## 版本管理与变更审计 +系统提供了实体定义的版本管理和变更审计功能,确保数据变更的可追溯性。 + +### 变更审计流程 +```mermaid +flowchart TD +Start([开始]) --> CheckChange["检查实体定义变更"] +CheckChange --> HasChange{"有变更?"} +HasChange --> |是| RecordChange["记录变更到dv_catalog_schema_change"] +HasChange --> |否| End([结束]) +RecordChange --> Notify["触发变更通知"] +Notify --> UpdateEntity["更新实体定义"] +UpdateEntity --> End +``` + +**Section sources** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L201-L213) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L201-L210) + +## 最佳实践 +### 实体分类体系设计 +1. **分层设计**: 建立清晰的实体层级结构,如:数据源 -> 数据库 -> 表 -> 列 +2. **命名规范**: 采用统一的命名约定,便于搜索和管理 +3. **属性标准化**: 定义标准的属性模板,确保一致性 +4. **权限控制**: 根据业务需求设置适当的访问权限 + +### 性能优化建议 +- 为常用查询字段创建索引 +- 定期清理过期的实体定义 +- 使用缓存减少数据库查询 + +## 常见问题解决 +### 定义冲突 +当出现实体定义冲突时,系统会通过UUID进行唯一性校验,拒绝重复的定义创建。 + +### 字段类型不匹配 +系统通过`StructField`类定义字段类型,确保与数据源的实际类型一致: +```mermaid +classDiagram +class StructField { ++String name ++DataType dataType ++boolean nullable ++String comment +} +class DataType { ++STRING ++INTEGER ++LONG ++DOUBLE ++BOOLEAN ++TIMESTAMP ++DECIMAL +} +StructField --> DataType : "引用" +``` + +**Diagram sources** +- [StructField.java](file://datavines-connector/ datavines-connector-api/src/main/java/io/datavines/connector/api/entity/StructField.java#L23-L32) +- [DataType.java](file://datavines-common/src/main/java/io/datavines/common/enums/DataType.java) + +**Section sources** +- [StructField.java](file://datavines-connector/ datavines-connector-api/src/main/java/io/datavines/connector/api/entity/StructField.java#L23-L32) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\256\236\344\275\223\345\256\236\344\276\213.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\256\236\344\275\223\345\256\236\344\276\213.md" new file mode 100644 index 00000000..4a8b4dbe --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\205\203\346\225\260\346\215\256\347\256\241\347\220\206/\345\256\236\344\275\223\345\256\236\344\276\213.md" @@ -0,0 +1,255 @@ +# 实体实例 + + +**本文档中引用的文件** +- [CatalogEntityInstance.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\catalog\CatalogEntityInstance.java) +- [CatalogEntityInstanceService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\CatalogEntityInstanceService.java) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CatalogEntityInstanceServiceImpl.java) +- [CatalogEntityDefinition.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\catalog\CatalogEntityDefinition.java) +- [CatalogEntityRel.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\catalog\CatalogEntityRel.java) +- [CatalogEntityProfile.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\catalog\CatalogEntityProfile.java) +- [CatalogController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\CatalogController.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server\src\main\java\io\datavines\server\scheduler\metadata\task\CatalogMetaDataFetchExecutorImpl.java) + + +## 目录 +1. [实体实例结构与字段说明](#实体实例结构与字段说明) +2. [实例与定义的关系模型](#实例与定义的关系模型) +3. [创建与管理实体实例](#创建与管理实体实例) +4. [实例数据验证与清洗流程](#实例数据验证与清洗流程) +5. [实例生命周期管理](#实例生命周期管理) +6. [批量操作与数据导入导出](#批量操作与数据导入导出) +7. [常见问题处理](#常见问题处理) + +## 实体实例结构与字段说明 + +`CatalogEntityInstance` 类是数据目录中实体实例的核心数据结构,用于表示数据库、表、列等元数据对象的具体实例。该类定义在 `CatalogEntityInstance.java` 文件中,其主要字段含义如下: + +- **id**: 实体实例的自增主键,类型为 `Long`,由数据库自动生成。 +- **uuid**: 实体实例的唯一标识符,类型为 `String`,用于跨系统引用和关联。 +- **datasourceId**: 关联的数据源ID,类型为 `Long`,表示该实例所属的数据源。 +- **type**: 实体类型,类型为 `String`,常见的值包括 "database"(数据库)、"table"(表)、"column"(列)等。 +- **fullyQualifiedName**: 完全限定名,类型为 `String`,表示该实体的完整路径名称,如 "database.table.column"。 +- **displayName**: 显示名称,类型为 `String`,用于在用户界面中展示的名称。 +- **description**: 描述信息,类型为 `String`,提供关于该实体的详细说明。 +- **properties**: 属性信息,类型为 `String`,以JSON格式存储实体的额外属性,如列的数据类型、是否为主键等。 +- **owner**: 所有者,类型为 `String`,标识该实体的负责人或拥有者。 +- **version**: 版本号,类型为 `String`,用于跟踪实体的版本变化。 +- **status**: 状态,类型为 `String`,表示实体的当前状态,如激活、已删除等。 +- **createTime**: 创建时间,类型为 `LocalDateTime`,记录实体的创建时间。 +- **updateBy**: 更新人ID,类型为 `Long`,记录最后更新该实体的用户ID。 +- **updateTime**: 更新时间,类型为 `LocalDateTime`,记录实体的最后更新时间。 + +这些字段共同构成了实体实例的完整信息模型,支持对数据资产的全面管理和查询。 + +**Section sources** +- [CatalogEntityInstance.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\catalog\CatalogEntityInstance.java) + +## 实例与定义的关系模型 + +实体实例与实体定义之间通过 `CatalogEntityDefinition` 类建立关联。`CatalogEntityDefinition` 表示实体的元数据定义,包含名称、描述、属性等信息,而 `CatalogEntityInstance` 则是这些定义的具体实现。两者通过 `uuid` 字段进行关联,确保每个实例都有对应的定义。 + +此外,实体之间的层级关系通过 `CatalogEntityRel` 类来维护。该类定义了实体间的关联关系,主要字段包括: +- **entity1Uuid**: 关系中的上游实体UUID。 +- **entity2Uuid**: 关系中的下游实体UUID。 +- **type**: 关系类型,如 "CHILD" 表示父子关系。 + +例如,一个数据库实例(entity1)与其包含的表实例(entity2)之间通过 `CatalogEntityRel` 建立 "CHILD" 类型的关系。这种设计支持灵活的元数据层级结构,便于实现目录浏览、影响分析等功能。 + +```mermaid +classDiagram +class CatalogEntityInstance { ++Long id ++String uuid ++Long datasourceId ++String type ++String fullyQualifiedName ++String displayName ++String description ++String properties ++String owner ++String version ++String status ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +class CatalogEntityDefinition { ++Long id ++String uuid ++String name ++String description ++String properties ++String superUuid ++Long createBy ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +class CatalogEntityRel { ++Long id ++String entity1Uuid ++String entity2Uuid ++String type ++Long updateBy ++LocalDateTime updateTime +} +CatalogEntityInstance --> CatalogEntityDefinition : "关联定义" +CatalogEntityInstance --> CatalogEntityRel : "作为entity2" +CatalogEntityRel --> CatalogEntityInstance : "作为entity1" +``` + +**Diagram sources ** +- [CatalogEntityInstance.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\catalog\CatalogEntityInstance.java) +- [CatalogEntityDefinition.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\catalog\CatalogEntityDefinition.java) +- [CatalogEntityRel.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\catalog\CatalogEntityRel.java) + +## 创建与管理实体实例 + +### 创建实体实例 + +通过 `CatalogEntityInstanceService` 接口的 `create` 方法可以创建新的实体实例。该方法接收一个 `CatalogEntityInstance` 对象作为参数,并将其插入数据库。创建成功后返回实例的 `uuid`。 + +```java +String create(CatalogEntityInstance entityInstance); +``` + +### API调用示例 + +以下是一个创建表实体实例的API调用示例: + +```http +POST /api/v1/catalog/entity +Content-Type: application/json + +{ + "datasourceId": 1, + "type": "table", + "fullyQualifiedName": "mydb.mytable", + "displayName": "My Table", + "description": "This is a sample table", + "properties": "{\"columns\":[{\"name\":\"id\",\"type\":\"INT\",\"primaryKey\":true},{\"name\":\"name\",\"type\":\"VARCHAR\"}]}" +} +``` + +### 管理实体实例 + +`CatalogEntityInstanceService` 提供了多种方法来管理实体实例: +- `getByTypeAndFQN`: 根据类型和完全限定名获取实体实例。 +- `getEntityList`: 获取指定上游实体下的所有子实体列表。 +- `getDatabaseEntityDetail`, `getTableEntityDetail`, `getColumnEntityDetail`: 分别获取数据库、表、列的详细信息。 +- `deleteEntityByUUID`: 根据UUID删除实体实例及其所有子实体。 + +这些方法支持对实体实例的全生命周期管理,包括查询、更新和删除操作。 + +**Section sources** +- [CatalogEntityInstanceService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\CatalogEntityInstanceService.java) +- [CatalogController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\CatalogController.java) + +## 实例数据验证与清洗流程 + +实体实例的数据验证和清洗主要在元数据抓取过程中完成。`CatalogMetaDataFetchExecutorImpl` 类负责从数据源中提取元数据并创建或更新实体实例。 + +当从数据源获取到新的元数据时,系统会执行以下步骤: +1. 查询数据库中是否存在具有相同 `uuid` 的现有实例。 +2. 如果存在,则更新其 `properties` 和 `description` 字段,并设置 `updateTime`。 +3. 如果不存在,则创建新的实例,生成新的 `uuid`。 + +```java +private String createOrUpdateCatalogEntityInstance(CatalogEntityInstance entityInstance, CatalogEntityInstance entityInstanceOld) { + String entityUUID; + if (entityInstanceOld != null) { + entityInstanceOld.setProperties(entityInstance.getProperties()); + entityInstanceOld.setDescription(entityInstance.getDescription()); + entityInstanceOld.setUpdateTime(LocalDateTime.now()); + instanceService.updateById(entityInstanceOld); + entityUUID = entityInstanceOld.getUuid(); + } else { + entityInstance.setUuid(UUID.randomUUID().toString()); + instanceService.create(entityInstance); + entityUUID = entityInstance.getUuid(); + } + return entityUUID; +} +``` + +此流程确保了元数据的准确性和一致性,同时保留了历史变更记录。对于属性字段中的JSON数据,系统会在解析时进行基本的格式验证,确保其为有效的JSON字符串。 + +**Section sources** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server\src\main\java\io\datavines\server\scheduler\metadata\task\CatalogMetaDataFetchExecutorImpl.java) + +## 实例生命周期管理 + +### 状态变更 + +实体实例的状态通过 `status` 字段进行管理。系统支持以下状态: +- **ACTIVE**: 激活状态,表示实体正常可用。 +- **DELETED**: 已删除状态,表示实体已被软删除。 + +状态变更通过 `updateStatus` 方法实现,该方法接收实例的 `uuid` 和目标状态作为参数。 + +### 归档与删除策略 + +系统采用软删除策略来管理实体实例的删除操作。`softDeleteEntityByDataSourceAndFQN` 方法会将实例的状态设置为 `"DELETED_<随机UUID>"`,而不是直接从数据库中物理删除记录。这有助于保留历史数据和审计信息。 + +对于需要彻底删除的场景,`deleteEntityByUUID` 方法会递归删除指定实例及其所有子实体,并清理相关的关联关系和度量任务。 + +```mermaid +flowchart TD +Start([开始]) --> CheckExistence{实例是否存在?} +CheckExistence --> |否| ReturnError[返回错误] +CheckExistence --> |是| CheckChildren{是否有子实体?} +CheckChildren --> |是| DeleteChildren[递归删除子实体] +DeleteChildren --> DeleteSelf[删除自身] +CheckChildren --> |否| DeleteSelf +DeleteSelf --> DeleteRelations[删除关联关系] +DeleteRelations --> DeleteMetrics[删除度量任务] +DeleteMetrics --> End([结束]) +``` + +**Diagram sources ** +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CatalogEntityInstanceServiceImpl.java) + +## 批量操作与数据导入导出 + +虽然当前代码库中未直接提供批量导入导出功能的实现,但可以通过以下方式实现: + +### 批量创建 + +通过循环调用 `create` 方法,可以批量创建多个实体实例。建议在事务中执行以确保数据一致性。 + +### 数据导出 + +利用 `getEntityList` 和 `getEntityPage` 方法,可以分页获取实体实例列表,并将其导出为JSON、CSV等格式。 + +### 数据导入 + +编写脚本解析导入文件,将每条记录转换为 `CatalogEntityInstance` 对象,然后调用 `create` 方法进行批量插入。 + +未来可扩展 `CatalogController` 添加专门的批量导入导出API端点,以提供更友好的用户接口。 + +**Section sources** +- [CatalogEntityInstanceService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\CatalogEntityInstanceService.java) + +## 常见问题处理 + +### 实例数据不一致 + +当发现实体实例数据与数据源实际状态不一致时,可通过触发元数据刷新任务来同步数据。调用 `/catalog/refresh` API 可启动刷新流程,系统将重新抓取元数据并更新所有相关实例。 + +### 关联丢失 + +如果发现实体间的关联关系丢失,首先检查 `CatalogEntityRel` 表中是否存在正确的记录。若记录缺失,可通过重新执行元数据抓取任务来重建关联。确保在抓取过程中正确维护 `entity1Uuid` 和 `entity2Uuid` 的对应关系。 + +### 性能优化建议 + +对于大规模元数据管理,建议: +1. 对 `uuid`、`fullyQualifiedName` 等常用查询字段建立索引。 +2. 使用分页查询避免一次性加载过多数据。 +3. 定期清理已删除的实体实例,减少数据库负担。 + +通过以上措施,可有效解决常见问题并提升系统性能。 + +**Section sources** +- [CatalogController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\CatalogController.java) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\CatalogEntityInstanceServiceImpl.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\217\230\346\233\264\346\243\200\346\265\213.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\217\230\346\233\264\346\243\200\346\265\213.md" new file mode 100644 index 00000000..fba0883e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\217\230\346\233\264\346\243\200\346\265\213.md" @@ -0,0 +1,258 @@ +# 变更检测 + + +**本文档引用的文件** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) +- [CatalogSchemaChangeService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogSchemaChangeService.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) + + +## 目录 +1. [引言](#引言) +2. [元数据变更检测架构](#元数据变更检测架构) +3. [调度架构与Quartz配置](#调度架构与quartz配置) +4. [CatalogMetaDataFetchExecutor实现机制](#catalogmetadatafetchexecutor实现机制) +5. [变更检测算法工作原理](#变更检测算法工作原理) +6. [性能优化建议](#性能优化建议) +7. [常见问题与解决方案](#常见问题与解决方案) +8. [结论](#结论) + +## 引言 + +DataVines是一个数据质量平台,其核心功能之一是元数据变更检测。该功能能够自动发现数据源中数据库、表和列的结构变化,包括新增、删除和修改等操作。通过定期采集元数据并与历史快照进行对比,系统可以及时识别出数据结构的变化,从而帮助用户监控数据资产的演化过程。本文档将深入解析DataVines中元数据变更检测的实现机制,涵盖从调度架构到具体执行流程的各个方面。 + +## 元数据变更检测架构 + +DataVines的元数据变更检测功能采用分层架构设计,主要包括调度层、执行层和存储层。调度层负责管理任务的触发时机,执行层负责具体的元数据采集和对比逻辑,存储层则用于保存元数据快照和变更记录。 + +```mermaid +graph TD +A[调度层] --> |触发| B[执行层] +B --> |采集| C[数据源] +B --> |存储| D[元数据存储] +B --> |记录| E[变更日志] +F[用户界面] --> |配置| A +F --> |查看| E +``` + +**图示来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L31-L91) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L59-L716) + +## 调度架构与Quartz配置 + +DataVines使用Quartz作为任务调度框架,实现了灵活的定时任务管理。调度架构的核心组件是`QuartzExecutors`类,它封装了Quartz Scheduler的所有操作,提供了添加、删除和查询任务的功能。 + +### 调度流程 + +调度流程始于`CommonTaskScheduler`线程,该线程持续轮询任务队列,当检测到新的元数据采集任务时,将其提交给任务管理器执行。整个流程如下: + +```mermaid +sequenceDiagram +participant Scheduler as CommonTaskScheduler +participant JobService as JobExternalService +participant TaskManager as CommonTaskManager +participant Executor as CatalogMetaDataFetchTaskRunner +Scheduler->>JobService : getCatalogCommand() +JobService-->>Scheduler : 返回任务命令 +Scheduler->>JobService : executeCatalogCommand() +JobService-->>Scheduler : 返回任务实例 +Scheduler->>TaskManager : putCommonTask() +TaskManager-->>Scheduler : 确认接收 +Scheduler->>JobService : deleteCatalogCommandById() +Executor->>CatalogMetaDataFetchExecutorImpl : 创建执行器实例 +Executor->>CatalogMetaDataFetchExecutorImpl : 执行execute() +``` + +**图示来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L47-L89) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java#L39-L51) + +### Quartz配置 + +Quartz的配置主要通过`QuartzExecutors`类实现,关键配置包括: + +- **Cron表达式**:定义任务的执行频率 +- **起始时间**:任务开始执行的时间点 +- **结束时间**:任务停止执行的时间点 +- **时区处理**:确保任务在正确的时区下执行 + +配置参数通过`ScheduleJobInfo`对象传递,其中包含了任务类型、数据源ID、Cron表达式等信息。系统还提供了验证Cron表达式有效性的功能,确保配置的正确性。 + +**变更来源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L58-L264) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L1-L42) + +## CatalogMetaDataFetchExecutor实现机制 + +`CatalogMetaDataFetchExecutor`是元数据采集的核心接口,其具体实现为`CatalogMetaDataFetchExecutorImpl`类。该类负责连接不同的数据源并获取最新的元数据信息。 + +### 数据源连接 + +执行器通过`ConnectorFactory`插件机制连接不同类型的数据库。系统支持多种数据源类型,包括MySQL、PostgreSQL、Oracle等。连接过程如下: + +1. 根据数据源类型获取对应的连接器工厂 +2. 使用数据源参数创建连接 +3. 执行元数据查询操作 + +```java +this.connectorFactory = PluginLoader + .getPluginLoader(ConnectorFactory.class) + .getOrCreatePlugin(dataSource.getType()); +``` + +### 采集流程 + +采集流程分为三个层次:数据源级、数据库级和表级。每个层次都遵循相同的模式:获取当前状态、与历史状态对比、识别变更、记录结果。 + +```mermaid +flowchart TD +Start([开始]) --> FetchDataSource["获取数据源中的数据库列表"] +FetchDataSource --> CompareDB["与数据库中存储的列表对比"] +CompareDB --> IdentifyDBChanges["识别新增和删除的数据库"] +IdentifyDBChanges --> RecordDBChanges["记录数据库变更"] +RecordDBChanges --> FetchTables["获取数据库中的表列表"] +FetchTables --> CompareTables["与数据库中存储的列表对比"] +CompareTables --> IdentifyTableChanges["识别新增和删除的表"] +IdentifyTableChanges --> RecordTableChanges["记录表变更"] +RecordTableChanges --> FetchColumns["获取表中的列列表"] +FetchColumns --> CompareColumns["与数据库中存储的列表对比"] +CompareColumns --> IdentifyColumnChanges["识别新增、删除和修改的列"] +IdentifyColumnChanges --> RecordColumnChanges["记录列变更"] +RecordColumnChanges --> End([结束]) +``` + +**变更来源** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L59-L716) + +## 变更检测算法工作原理 + +变更检测算法的核心是比较当前采集的元数据与存储在数据库中的历史快照,识别出各种类型的变更。算法支持多种变更类型,每种类型都有对应的处理逻辑。 + +### 变更类型 + +系统定义了多种变更类型,通过`SchemaChangeType`枚举类进行管理: + +| 变更类型 | 描述 | 代码 | +|---------|------|------| +| DATABASE_ADDED | 数据库新增 | 0 | +| DATABASE_DELETED | 数据库删除 | 1 | +| TABLE_ADDED | 表新增 | 2 | +| TABLE_DELETED | 表删除 | 3 | +| TABLE_COMMENT_CHANGE | 表注释变更 | 4 | +| COLUMN_ADDED | 列新增 | 5 | +| COLUMN_DELETED | 列删除 | 6 | +| COLUMN_TYPE_CHANGE | 列类型变更 | 7 | +| COLUMN_COMMENT_CHANGE | 列注释变更 | 8 | + +**变更来源** +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java#L24-L38) + +### 对比逻辑 + +对比逻辑采用三路比较方法,分别处理新增、删除和修改三种情况: + +1. **新增检测**:遍历当前列表,查找在历史列表中不存在的项 +2. **删除检测**:遍历历史列表,查找在当前列表中不存在的项 +3. **修改检测**:对同时存在于两个列表中的项,比较其属性是否发生变化 + +对于列级别的变更检测,系统特别关注类型和注释的变化: + +```java +private boolean isTypeChange(String oldType, String newType) { + if (StringUtils.isEmpty(oldType) && StringUtils.isNotEmpty(newType)) { + return true; + } + if (StringUtils.isEmpty(newType) && StringUtils.isNotEmpty(oldType)) { + return true; + } + return StringUtils.isNotEmpty(newType) && StringUtils.isNotEmpty(oldType) && !oldType.equals(newType); +} +``` + +检测到的变更会被记录到`CatalogSchemaChange`表中,供后续查询和分析使用。 + +**变更来源** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L692-L714) +- [CatalogSchemaChangeService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogSchemaChangeService.java#L1-L30) + +## 性能优化建议 + +为了提高元数据变更检测的效率和稳定性,系统提供了多种性能优化策略。 + +### 增量采集策略 + +系统默认采用增量采集策略,只采集发生变化的部分。对于首次采集,会获取完整的元数据;后续采集则只关注变更。这种策略大大减少了网络传输和处理时间。 + +### 采样频率配置 + +采样频率通过Cron表达式进行配置,可以根据实际需求调整。建议遵循以下原则: + +- **高变更频率的数据源**:每小时采集一次(`0 * * * * ?`) +- **中等变更频率的数据源**:每天采集一次(`0 0 2 * * ?`) +- **低变更频率的数据源**:每周采集一次(`0 0 2 ? * MON`) + +配置参数可以在`common.properties`文件中进行全局设置: + +```properties +# 全局配置示例 +registry.type=default +registry.failover.key=1024 +``` + +### 资源限制 + +系统内置了资源检查机制,确保在系统负载过高时不执行采集任务: + +```java +boolean runCheckFlag = OSUtils.checkResource( + CommonPropertyUtils.getDouble(MAX_CPU_LOAD_AVG, MAX_CPU_LOAD_AVG_DEFAULT), + CommonPropertyUtils.getDouble(RESERVED_MEMORY, RESERVED_MEMORY_DEFAULT)); +``` + +**变更来源** +- [common.properties](file://datavines-common/src/main/resources/common.properties#L1-L25) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L55-L58) + +## 常见问题与解决方案 + +### 变更检测延迟 + +**问题描述**:变更检测结果出现延迟,不能及时反映数据源的实际变化。 + +**解决方案**: +1. 检查Cron表达式配置是否正确 +2. 确认调度服务是否正常运行 +3. 检查系统资源是否充足 +4. 查看任务执行日志是否有错误信息 + +### 数据源连接超时 + +**问题描述**:在采集过程中出现连接超时错误。 + +**解决方案**: +1. 检查网络连接是否稳定 +2. 确认数据库服务是否正常运行 +3. 调整连接超时参数 +4. 检查防火墙设置是否阻止了连接 + +### 变更记录不完整 + +**问题描述**:某些变更没有被正确记录。 + +**解决方案**: +1. 检查`SchemaChangeType`枚举是否包含所有需要的变更类型 +2. 确认对比逻辑是否覆盖了所有属性 +3. 查看数据库存储是否正常 +4. 检查权限设置是否允许读取所有元数据 + +**变更来源** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L308-L311) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L82-L87) + +## 结论 + +DataVines的元数据变更检测功能通过精心设计的架构和高效的算法,实现了对数据源结构变化的全面监控。系统采用Quartz作为调度框架,确保了任务的可靠执行;通过`CatalogMetaDataFetchExecutor`接口和实现类,支持多种数据源的连接和元数据采集;利用精细的对比算法,能够准确识别各种类型的变更。此外,系统还提供了丰富的性能优化选项和故障排查指南,确保在各种生产环境中都能稳定运行。未来可以考虑增加更多类型的变更检测,如索引变更、约束变更等,进一步完善元数据管理能力。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\217\230\346\233\264\347\233\221\346\216\247.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\217\230\346\233\264\347\233\221\346\216\247.md" new file mode 100644 index 00000000..9435bad4 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\217\230\346\233\264\347\233\221\346\216\247.md" @@ -0,0 +1,219 @@ +# 变更监控 + + +**本文档引用的文件** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) +- [CatalogSchemaChangeServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogSchemaChangeServiceImpl.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) + + +## 目录 +1. [引言](#引言) +2. [核心实体结构](#核心实体结构) +3. [变更检测算法](#变更检测算法) +4. [元数据采集调度机制](#元数据采集调度机制) +5. [变更通知配置](#变更通知配置) +6. [变更影响分析](#变更影响分析) +7. [变更审批流程](#变更审批流程) +8. [常见问题与解决方案](#常见问题与解决方案) +9. [总结](#总结) + +## 引言 +DataVines 是一个数据质量管理平台,其变更监控功能用于跟踪和记录数据目录中元数据的结构变化。该功能通过定期采集元数据并与历史记录进行对比,识别出新增、修改或删除的数据表和列等变更,并将这些变更记录下来,支持通知、影响分析和审批等后续处理。本文档详细解释了 DataVines 中变更监控功能的实现机制。 + +## 核心实体结构 +变更监控功能的核心是 `CatalogSchemaChange` 实体,它用于记录每一次元数据结构的变更。 + +### CatalogSchemaChange 实体 +`CatalogSchemaChange` 实体定义了变更记录的数据结构,其主要字段包括: +- **id**: 主键,自增。 +- **parentUuid**: 父级实体的唯一标识符(UUID),例如数据库实例的 UUID。 +- **entityUuid**: 发生变更的实体的唯一标识符(UUID),例如数据表或列的 UUID。 +- **changeType**: 变更类型,使用 `SchemaChangeType` 枚举定义,如新增数据库、删除表、修改列类型等。 +- **databaseName**: 数据库名称。 +- **tableName**: 表名称。 +- **columnName**: 列名称。 +- **changeBefore**: 变更前的值(如旧的列类型或注释)。 +- **changeAfter**: 变更后的值(如新的列类型或注释)。 +- **updateTime**: 变更发生的时间。 + +该实体映射到数据库表 `dv_catalog_schema_change`,用于持久化存储所有的变更历史。 + +**Section sources** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java#L30-L70) + +### SchemaChangeType 枚举 +`SchemaChangeType` 枚举定义了所有可能的变更类型,为变更记录提供了标准化的分类。其主要类型包括: +- `DATABASE_ADDED`: 数据库新增 +- `DATABASE_DELETED`: 数据库删除 +- `TABLE_ADDED`: 数据表新增 +- `TABLE_DELETED`: 数据表删除 +- `TABLE_COMMENT_CHANGE`: 数据表注释变更 +- `COLUMN_ADDED`: 列新增 +- `COLUMN_DELETED`: 列删除 +- `COLUMN_TYPE_CHANGE`: 列类型变更 +- `COLUMN_COMMENT_CHANGE`: 列注释变更 + +该枚举通过 `code` 和 `description` 两个字段来标识每种变更类型,并提供了一个静态的 `SCHEMA_CHANGE_TYPE_MAP` 来实现高效的类型查找。 + +**Section sources** +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java#L24-L74) + +## 变更检测算法 +变更检测算法是变更监控功能的核心,它负责识别元数据中的具体变化。 + +### 算法工作原理 +变更检测算法采用“全量对比”的策略。其工作流程如下: +1. **采集当前元数据**:通过 `Connector` 插件连接到数据源,获取当前所有数据库、表和列的元数据信息。 +2. **获取历史元数据**:从 DataVines 的元数据存储中查询出该数据源对应的历史元数据记录。 +3. **逐级对比**: + * **数据库级对比**:将当前数据库列表与历史数据库列表进行对比,找出新增和删除的数据库。 + * **表级对比**:对每个数据库,将当前表列表与历史表列表进行对比,找出新增和删除的表。 + * **列级对比**:对每个表,将当前列列表与历史列列表进行对比,找出新增和删除的列。 +4. **属性变更检测**:对于在历史记录中存在但在当前也存在的表或列,进一步对比其关键属性(如注释、类型)是否发生变化。 + * `isCommentChange` 方法用于判断注释是否变更。 + * `isTypeChange` 方法用于判断类型是否变更。 + +### 识别变更类型 +通过上述对比过程,系统可以精确地识别出不同类型的变更: +- **新增**:在当前元数据中存在,但在历史元数据中不存在的实体(数据库、表、列)。 +- **删除**:在历史元数据中存在,但在当前元数据中不存在的实体。 +- **修改**:在当前和历史元数据中都存在的实体,但其属性(如注释、类型)发生了变化。 + +当检测到任何变更时,系统会创建一个 `CatalogSchemaChange` 实体实例,并将其保存到数据库中。 + +```mermaid +flowchart TD +Start([开始变更检测]) --> FetchCurrent["采集当前元数据"] +FetchCurrent --> FetchHistory["获取历史元数据"] +FetchHistory --> CompareDB["对比数据库列表"] +CompareDB --> NewDB{"发现新增数据库?"} +NewDB --> |是| RecordAddDB["记录 DATABASE_ADDED 变更"] +NewDB --> |否| DeleteDB{"发现删除数据库?"} +DeleteDB --> |是| RecordDelDB["记录 DATABASE_DELETED 变更"] +DeleteDB --> |否| CompareTable["对比表列表"] +CompareTable --> NewTable{"发现新增表?"} +NewTable --> |是| RecordAddTable["记录 TABLE_ADDED 变更"] +NewTable --> |否| DeleteTable{"发现删除表?"} +DeleteTable --> |是| RecordDelTable["记录 TABLE_DELETED 变更"] +DeleteTable --> |否| CheckTableComment["检查表注释是否变更"] +CheckTableComment --> ChangeComment{"注释变更?"} +ChangeComment --> |是| RecordCommentChange["记录 TABLE_COMMENT_CHANGE 变更"] +ChangeComment --> |否| CompareColumn["对比列列表"] +CompareColumn --> NewColumn{"发现新增列?"} +NewColumn --> |是| RecordAddColumn["记录 COLUMN_ADDED 变更"] +NewColumn --> |否| DeleteColumn{"发现删除列?"} +DeleteColumn --> |是| RecordDelColumn["记录 COLUMN_DELETED 变更"] +DeleteColumn --> |否| CheckColumnType["检查列类型是否变更"] +CheckColumnType --> ChangeType{"类型变更?"} +ChangeType --> |是| RecordTypeChange["记录 COLUMN_TYPE_CHANGE 变更"] +ChangeType --> |否| CheckColumnComment["检查列注释是否变更"] +CheckColumnComment --> ChangeColComment{"注释变更?"} +ChangeColComment --> |是| RecordColCommentChange["记录 COLUMN_COMMENT_CHANGE 变更"] +ChangeColComment --> |否| End([结束]) +RecordAddDB --> End +RecordDelDB --> End +RecordAddTable --> End +RecordDelTable --> End +RecordCommentChange --> End +RecordAddColumn --> End +RecordDelColumn --> End +RecordTypeChange --> End +RecordColCommentChange --> End +``` + +**Diagram sources** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L108-L715) + +**Section sources** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L91-L715) + +## 元数据采集调度机制 +元数据的自动采集由一个独立的调度系统驱动,确保变更能够被及时发现。 + +### 调度流程 +1. **调度器启动**:`CommonTaskScheduler` 作为一个后台线程运行,它会周期性地检查是否有新的采集任务需要执行。 +2. **任务获取**:调度器通过 `JobExternalService` 从任务队列中获取 `CatalogCommand`(元数据采集命令)。 +3. **任务提交**:当获取到命令后,调度器会调用 `CommonTaskManager` 的 `putCommonTask` 方法,将命令包装成一个 `CommonTask` 并放入内部的任务队列 `taskQueue` 中。 +4. **任务执行**:`CommonTaskManager` 内部有一个 `TaskExecutor` 线程,它会持续从 `taskQueue` 中取出任务。对于元数据采集任务,它会创建一个 `CatalogMetaDataFetchTaskRunner` 实例并在线程池中执行。 +5. **执行器处理**:`CatalogMetaDataFetchTaskRunner` 会调用 `CatalogMetaDataFetchExecutorImpl` 的 `execute` 方法,开始执行具体的元数据采集和变更检测逻辑。 + +### 定时任务配置 +定时任务的触发通常由外部系统(如调度平台)通过 API 向 DataVines 提交 `CatalogCommand` 来实现。具体的执行频率(如每小时一次)是在外部调度系统中配置的,DataVines 的 `CommonTaskScheduler` 负责响应这些定时触发的命令。 + +```mermaid +sequenceDiagram +participant Scheduler as CommonTaskScheduler +participant Manager as CommonTaskManager +participant TaskRunner as CatalogMetaDataFetchTaskRunner +participant Executor as CatalogMetaDataFetchExecutorImpl +Scheduler->>Scheduler : 启动并循环 +Scheduler->>JobExternalService : getCatalogCommand() +JobExternalService-->>Scheduler : 返回 CatalogCommand +Scheduler->>Manager : putCommonTask(command) +Manager->>Manager : 创建 CommonTaskContext +Manager->>Manager : 将任务放入 taskQueue +Manager->>TaskExecutor : 从 taskQueue 取出任务 +TaskExecutor->>TaskRunner : execute() +TaskRunner->>Executor : execute() +Executor->>DataSource : 采集元数据 +DataSource-->>Executor : 返回元数据 +Executor->>Executor : 执行变更检测算法 +Executor->>CatalogSchemaChangeService : 保存变更记录 +Executor-->>TaskRunner : 完成 +TaskRunner-->>TaskExecutor : 任务结束 +``` + +**Diagram sources** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L31-L91) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java#L38-L159) + +**Section sources** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L31-L91) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java#L38-L159) + +## 变更通知配置 +当检测到元数据变更时,系统可以配置多种通知渠道来提醒相关人员。 + +### 支持的通知渠道 +根据代码分析,系统支持通过插件化的方式集成多种通知渠道,目前已实现的包括: +- **邮件 (Email)** +- **钉钉 (DingTalk)** +- **飞书 (Lark)** +- **企业微信 (WeComBot)** + +### 配置方法 +通知的配置通常在变更事件的处理逻辑中完成。以钉钉通知为例: +1. 系统会创建一个 `SlaNotificationMessage` 对象,包含通知的主题和内容。 +2. 配置一个 `DingTalkSlasHandlerPlugin` 实例,该插件实现了 `SlasHandlerPlugin` 接口。 +3. 在插件配置中,指定钉钉机器人的 Webhook 地址、消息类型(文本或 Markdown)等参数。 +4. 调用插件的 `notify` 方法,将 `SlaNotificationMessage` 和配置信息传递给它,由插件负责将消息发送到钉钉群。 + +**Section sources** +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java#L28-L36) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java#L39-L52) + +## 变更影响分析 +文档中未找到关于变更影响分析功能的具体实现代码。该功能可能依赖于数据血缘(Data Lineage)分析,通过追踪变更的表或列在下游任务中的使用情况,来评估变更的影响范围。此功能的详细实现需要进一步查阅 `datavines-connector` 模块中的血缘解析相关代码。 + +## 变更审批流程 +文档中未找到关于变更审批流程的具体实现代码。变更审批可能是一个独立的工作流功能,允许用户在变更被应用到生产环境前进行审核和批准。该功能可能涉及创建审批任务、分配审批人、处理审批结果等逻辑,其具体实现需要查阅与工作流或任务审批相关的模块。 + +## 常见问题与解决方案 +### 变更检测延迟 +**问题**:变更发生后,系统未能立即检测到。 +**原因**:元数据采集是定时任务,存在执行间隔。例如,如果任务配置为每小时执行一次,那么变更最多可能需要等待一小时才能被发现。 +**解决方案**:缩短定时任务的执行周期,但这会增加系统负载。或者,实现基于事件的实时采集机制(如监听数据库的 DDL 事件),但这需要数据源的支持。 + +### 误报 +**问题**:系统报告了实际上并未发生的变更。 +**原因**:可能是由于元数据采集过程中出现网络抖动或临时错误,导致某次采集的结果不完整或不准确,从而与历史记录产生差异。 +**解决方案**:在变更检测逻辑中增加重试机制,对疑似变更进行二次确认。同时,确保 `Connector` 插件的稳定性和健壮性。 + +## 总结 +DataVines 的变更监控功能通过 `CatalogSchemaChange` 实体记录变更历史,利用 `CatalogMetaDataFetchExecutorImpl` 中的对比算法检测新增、删除和修改等变更类型,并由 `CommonTaskScheduler` 驱动的调度机制实现元数据的自动采集。系统支持通过邮件、钉钉等多种渠道进行变更通知。对于变更影响分析和审批流程,当前代码库中未提供足够的信息,可能需要进一步的功能开发或配置。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\217\230\346\233\264\351\200\232\347\237\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\217\230\346\233\264\351\200\232\347\237\245.md" new file mode 100644 index 00000000..3574268d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\217\230\346\233\264\351\200\232\347\237\245.md" @@ -0,0 +1,440 @@ +# 变更通知 + + +**本文档引用的文件** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java) +- [CatalogSchemaChangeService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogSchemaChangeService.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java) + + +## 目录 +1. [简介](#简介) +2. [变更通知系统架构](#变更通知系统架构) +3. [CatalogSchemaChange实体与变更事件](#catalogschemachange实体与变更事件) +4. [通知渠道配置](#通知渠道配置) +5. [通知模板与变量替换](#通知模板与变量替换) +6. [通知策略配置](#通知策略配置) +7. [通知状态跟踪与重试机制](#通知状态跟踪与重试机制) +8. [常见问题解决](#常见问题解决) +9. [总结](#总结) + +## 简介 + +DataVines的变更通知功能旨在为数据目录中的模式变更提供实时、可靠的告警机制。当数据源的表结构发生变更时,系统能够自动检测并触发通知事件,通过多种渠道将变更信息推送给相关人员。本文档详细说明了该功能的配置和使用方法,包括如何基于CatalogSchemaChange实体触发通知事件,支持邮件、钉钉、飞书、企业微信等多种通知渠道的配置方式,通知模板的自定义方法,以及通知策略的配置等。 + +**变更通知系统**的核心目标是确保数据治理团队能够及时了解数据资产的变化,从而快速响应潜在的数据质量问题或合规风险。该系统通过监听CatalogSchemaChange实体的创建和更新,实现了对数据模式变更的自动化监控。 + +## 变更通知系统架构 + +DataVines的变更通知系统采用插件化架构设计,通过SPI(Service Provider Interface)机制实现通知渠道的灵活扩展。系统核心由NotificationManager、SlasHandlerPlugin接口和具体的渠道插件组成。 + +```mermaid +graph TD +A[CatalogSchemaChange] --> |检测变更| B[通知事件] +B --> C[NotificationManager] +C --> D[SlasHandlerPlugin] +D --> E[钉钉插件] +D --> F[邮件插件] +D --> G[飞书插件] +D --> H[企业微信插件] +E --> I[钉钉群] +F --> J[收件人邮箱] +G --> K[飞书群] +H --> L[企业微信群] +``` + +**架构说明**: +- **CatalogSchemaChange**:数据目录中的模式变更实体,是通知事件的触发源。 +- **NotificationManager**:通知管理器,负责协调和分发通知请求。 +- **SlasHandlerPlugin**:通知处理插件接口,定义了通知发送的标准方法。 +- **具体渠道插件**:实现了SlasHandlerPlugin接口,负责与特定通知渠道的API进行交互。 + +**架构来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +**变更通知流程** +```mermaid +sequenceDiagram +participant Catalog as CatalogSchemaChange +participant Manager as NotificationManager +participant Plugin as SlasHandlerPlugin +participant DingTalk as 钉钉插件 +participant Email as 邮件插件 +participant Lark as 飞书插件 +participant WeCom as 企业微信插件 +Catalog->>Manager : 检测到模式变更 +Manager->>Plugin : 调用notify方法 +Plugin->>DingTalk : 发送钉钉通知 +Plugin->>Email : 发送邮件通知 +Plugin->>Lark : 发送飞书通知 +Plugin->>WeCom : 发送企业微信通知 +DingTalk-->>Manager : 返回发送结果 +Email-->>Manager : 返回发送结果 +Lark-->>Manager : 返回发送结果 +WeCom-->>Manager : 返回发送结果 +Manager-->>Catalog : 汇总所有结果 +``` + +**流程说明**: +1. 系统检测到CatalogSchemaChange实体的创建或更新。 +2. NotificationManager接收到通知请求。 +3. 根据配置的渠道类型,调用相应的SlasHandlerPlugin实现。 +4. 各插件通过API向对应的通知渠道发送消息。 +5. 插件返回发送结果,NotificationManager汇总后返回最终状态。 + +**流程来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +## CatalogSchemaChange实体与变更事件 + +CatalogSchemaChange实体是DataVines中用于记录数据目录模式变更的核心数据结构。当数据源的表结构发生变更时,系统会创建或更新该实体,从而触发变更通知事件。 + +```mermaid +classDiagram +class CatalogSchemaChange { ++Long id ++String entityUuid ++String parentUuid ++String entityName ++String entityType ++String operation ++String columnName ++String columnType ++String columnComment ++String beforeValue ++String afterValue ++String changeDescription ++SchemaChangeType changeType ++LocalDateTime createTime ++LocalDateTime updateTime +} +class SchemaChangeType { ++int code ++String description ++static SchemaChangeType of(Integer status) +} +CatalogSchemaChange --> SchemaChangeType : "包含" +``` + +**实体属性说明**: +- **id**:主键,自增。 +- **entityUuid**:变更实体的唯一标识。 +- **parentUuid**:父实体的唯一标识。 +- **entityName**:变更实体的名称。 +- **entityType**:变更实体的类型(如表、视图等)。 +- **operation**:操作类型(如ADD、DROP、ALTER等)。 +- **columnName**:涉及的列名。 +- **columnType**:列的数据类型。 +- **columnComment**:列的注释。 +- **beforeValue**:变更前的值。 +- **afterValue**:变更后的值。 +- **changeDescription**:变更描述。 +- **changeType**:变更类型,枚举值。 +- **createTime**:创建时间。 +- **updateTime**:更新时间。 + +**变更类型枚举**: +- **ADD_COLUMN**:添加列 +- **DROP_COLUMN**:删除列 +- **ALTER_COLUMN_TYPE**:修改列类型 +- **ALTER_COLUMN_COMMENT**:修改列注释 +- **ADD_INDEX**:添加索引 +- **DROP_INDEX**:删除索引 + +**实体来源** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) + +## 通知渠道配置 + +DataVines支持多种通知渠道的配置,包括邮件、钉钉、飞书和企业微信。每种渠道都有其特定的配置参数,通过SlasHandlerPlugin接口的实现来完成。 + +### 邮件通知配置 + +邮件通知通过EmailSlasHandlerPlugin实现,需要配置SMTP服务器和发件人信息。 + +```mermaid +flowchart TD +A[邮件通知配置] --> B[服务器主机] +A --> C[服务器端口] +A --> D[发件人邮箱] +A --> E[SMTP认证] +A --> F[用户名] +A --> G[密码] +A --> H[启用TLS] +A --> I[启用SSL] +A --> J[SSL信任] +``` + +**配置参数说明**: +- **serverHost**:SMTP服务器主机地址。 +- **serverPort**:SMTP服务器端口,默认25。 +- **sender**:发件人邮箱地址。 +- **enableSmtpAuth**:是否启用SMTP认证。 +- **user**:SMTP认证用户名。 +- **passwd**:SMTP认证密码。 +- **starttlsEnable**:是否启用STARTTLS。 +- **sslEnable**:是否启用SSL。 +- **smtpSslTrust**:是否信任SSL证书。 + +**配置来源** +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) + +### 钉钉通知配置 + +钉钉通知通过DingTalkSlasHandlerPlugin实现,需要配置Webhook和安全设置。 + +```mermaid +flowchart TD +A[钉钉通知配置] --> B[Webhook] +A --> C[密钥] +A --> D[关键词] +A --> E[@手机号] +A --> F[@钉钉ID] +A --> G[@所有人] +``` + +**配置参数说明**: +- **webhook**:钉钉群机器人的Webhook地址。 +- **secret**:钉钉群机器人的密钥。 +- **keyWord**:消息关键词,用于安全验证。 +- **atMobiles**:需要@的手机号列表。 +- **atDingtalkIds**:需要@的钉钉ID列表。 +- **isAtAll**:是否@所有人。 + +**配置来源** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) + +### 飞书通知配置 + +飞书通知通过LarkSlasHandlerPlugin实现,需要配置Webhook和通知范围。 + +```mermaid +flowchart TD +A[飞书通知配置] --> B[Webhook] +A --> C[@所有人] +``` + +**配置参数说明**: +- **webhook**:飞书群机器人的Webhook地址。 +- **atAll**:是否@所有人。 + +**配置来源** +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) + +### 企业微信通知配置 + +企业微信通知通过WecomBotSlasHandlerPlugin实现,需要配置Webhook。 + +```mermaid +flowchart TD +A[企业微信通知配置] --> B[Webhook] +``` + +**配置参数说明**: +- **webhook**:企业微信群机器人的Webhook地址。 + +**配置来源** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java) + +## 通知模板与变量替换 + +DataVines的变更通知系统支持灵活的通知模板配置,允许用户自定义消息内容,并通过变量替换实现动态信息的插入。 + +### 通知模板结构 + +通知模板由固定文本和变量占位符组成,系统在发送通知时会自动替换占位符为实际值。 + +```mermaid +flowchart TD +A[通知模板] --> B[固定文本] +A --> C[变量占位符] +C --> D[变更类型] +C --> E[实体名称] +C --> F[操作类型] +C --> G[列名] +C --> H[变更前值] +C --> I[变更后值] +C --> J[变更时间] +``` + +**变量占位符说明**: +- **{changeType}**:变更类型,如"添加列"、"删除列"等。 +- **{entityName}**:变更实体的名称。 +- **{operation}**:操作类型,如"ADD"、"DROP"等。 +- **{columnName}**:涉及的列名。 +- **{beforeValue}**:变更前的值。 +- **{afterValue}**:变更后的值。 +- **{changeTime}**:变更发生的时间。 + +### 模板格式化选项 + +系统支持多种格式化选项,以适应不同通知渠道的显示需求。 + +```mermaid +flowchart TD +A[模板格式化] --> B[纯文本] +A --> C[Markdown] +A --> D[HTML] +A --> E[卡片消息] +``` + +**格式化选项说明**: +- **纯文本**:适用于所有渠道,显示为普通文本。 +- **Markdown**:适用于支持Markdown的渠道,如钉钉、飞书。 +- **HTML**:适用于邮件等支持HTML的渠道。 +- **卡片消息**:适用于支持卡片消息的渠道,如飞书、企业微信。 + +**模板来源** +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) + +## 通知策略配置 + +DataVines提供了灵活的通知策略配置,允许用户根据业务需求选择不同的通知模式。 + +### 立即通知模式 + +立即通知模式在检测到变更后立即发送通知,适用于需要实时响应的场景。 + +```mermaid +flowchart TD +A[检测到变更] --> B[立即发送通知] +B --> C[通知成功] +C --> D[结束] +B --> E[通知失败] +E --> F[记录失败日志] +F --> G[结束] +``` + +**立即通知特点**: +- 实时性强,变更发生后立即通知。 +- 适用于关键数据资产的变更监控。 +- 可能产生较多通知,需谨慎配置。 + +### 汇总通知模式 + +汇总通知模式将一段时间内的变更进行汇总,定期发送通知,适用于变更频繁但不需要实时响应的场景。 + +```mermaid +flowchart TD +A[检测到变更] --> B[记录变更] +B --> C[等待汇总周期] +C --> D[汇总变更] +D --> E[发送汇总通知] +E --> F[通知成功] +F --> G[结束] +E --> H[通知失败] +H --> I[记录失败日志] +I --> J[结束] +``` + +**汇总通知特点**: +- 减少通知频率,避免信息过载。 +- 适用于非关键数据资产的变更监控。 +- 可配置汇总周期,如每小时、每天等。 + +**策略来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +## 通知状态跟踪与重试机制 + +DataVines的变更通知系统提供了完善的通知状态跟踪和重试机制,确保通知的可靠送达。 + +### 通知状态跟踪 + +系统会记录每条通知的发送状态,包括成功、失败和重试情况。 + +```mermaid +stateDiagram-v2 +[*] --> 待发送 +待发送 --> 发送中 : 开始发送 +发送中 --> 发送成功 : API返回成功 +发送中 --> 发送失败 : API返回失败 +发送失败 --> 重试中 : 触发重试 +重试中 --> 发送成功 : 重试成功 +重试中 --> 发送失败 : 重试次数超限 +发送成功 --> [*] +发送失败 --> [*] +``` + +**状态说明**: +- **待发送**:通知已创建,等待发送。 +- **发送中**:正在调用通知渠道API。 +- **发送成功**:API返回成功,通知已送达。 +- **发送失败**:API返回失败,通知未送达。 +- **重试中**:正在尝试重新发送。 + +### 重试机制 + +系统在通知失败时会自动触发重试机制,确保通知的最终送达。 + +```mermaid +flowchart TD +A[发送失败] --> B[记录失败] +B --> C[等待重试间隔] +C --> D[重试发送] +D --> E[发送成功] +E --> F[结束] +D --> G[发送失败] +G --> H[检查重试次数] +H --> I[重试次数未超限] +I --> C +H --> J[重试次数超限] +J --> K[标记为最终失败] +K --> L[结束] +``` + +**重试策略**: +- 可配置最大重试次数。 +- 可配置重试间隔时间。 +- 支持指数退避算法,避免对通知渠道造成过大压力。 + +**跟踪来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java) + +## 常见问题解决 + +### 通知延迟 + +**问题描述**:变更发生后,通知未能及时送达。 + +**可能原因**: +1. 系统负载过高,导致通知处理延迟。 +2. 通知渠道API响应缓慢。 +3. 网络问题导致请求超时。 + +**解决方案**: +1. 检查系统资源使用情况,优化性能。 +2. 联系通知渠道服务商,确认API状态。 +3. 检查网络连接,确保网络畅通。 + +### 消息丢失 + +**问题描述**:变更发生后,未收到任何通知。 + +**可能原因**: +1. 通知配置错误,导致消息无法发送。 +2. 通知渠道API返回成功,但实际未送达。 +3. 接收方设置问题,如邮箱过滤规则。 + +**解决方案**: +1. 检查通知配置,确保所有参数正确。 +2. 查看系统日志,确认通知发送状态。 +3. 检查接收方设置,确保消息未被过滤。 + +**问题来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +## 总结 + +DataVines的变更通知功能通过CatalogSchemaChange实体实现了对数据目录模式变更的自动化监控。系统采用插件化架构,支持邮件、钉钉、飞书、企业微信等多种通知渠道,提供了灵活的通知模板和策略配置。通过完善的通知状态跟踪和重试机制,确保了通知的可靠送达。该功能为数据治理团队提供了及时、准确的变更信息,有助于快速响应数据质量问题和合规风险。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\256\241\346\211\271\346\265\201\347\250\213.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\256\241\346\211\271\346\265\201\347\250\213.md" new file mode 100644 index 00000000..77845cfe --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\256\241\346\211\271\346\265\201\347\250\213.md" @@ -0,0 +1,125 @@ +# 审批流程 + + +**本文档引用的文件** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java) +- [CatalogSchemaChangeService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogSchemaChangeService.java) +- [CatalogSchemaChangeServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogSchemaChangeServiceImpl.java) +- [CatalogSchemaChangeMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogSchemaChangeMapper.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) + + +## 目录 +1. [简介](#简介) +2. [审批流程配置](#审批流程配置) +3. [状态机模型](#状态机模型) +4. [审计日志](#审计日志) +5. [超时处理与自动通过策略](#超时处理与自动通过策略) +6. [常见问题解决](#常见问题解决) + +## 简介 +DataVines系统提供了针对CatalogSchemaChange变更请求的审批流程功能,用于管理数据目录模式变更的审批过程。该功能允许用户配置审批规则、管理审批状态,并提供完整的审计跟踪。本文档详细说明了审批流程的配置和管理方法。 + +## 审批流程配置 + +DataVines中的变更审批流程主要针对CatalogSchemaChange实体进行管理。系统通过CatalogSchemaChange实体来记录所有模式变更请求,包括数据库、表和列级别的变更。审批规则的配置主要涉及变更类型、审批人和审批条件的设置。 + +CatalogSchemaChange实体包含以下关键字段用于审批流程配置: +- `changeType`: 变更类型,定义了变更的类别(如数据库添加、表删除、列类型变更等) +- `entityUuid`: 关联的实体UUID,用于标识变更的目标 +- `updateBy`: 发起变更的用户ID +- `updateTime`: 变更时间戳 + +审批人配置通常与工作空间或项目级别的权限设置相关联,系统根据用户角色和权限自动确定审批链。审批条件可以根据变更的敏感程度和影响范围进行配置,例如对生产环境的变更需要更严格的审批流程。 + +**审批流程配置** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java#L30-L70) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java#L24-L38) + +## 状态机模型 + +审批流程的状态机模型基于CatalogSchemaChange实体的生命周期管理。虽然在提供的代码中没有明确的状态字段,但可以推断出系统实现了以下状态转换逻辑: + +```mermaid +stateDiagram-v2 +[*] --> 待审批 +待审批 --> 已批准 : 审批通过 +待审批 --> 已拒绝 : 审批拒绝 +待审批 --> 已撤销 : 发起人撤销 +已批准 --> 已实施 : 变更执行 +已拒绝 --> 已关闭 : 流程结束 +已撤销 --> 已关闭 : 流程结束 +已实施 --> 已关闭 : 流程完成 +``` + +**状态机来源** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java#L30-L70) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java#L24-L38) + +**状态机说明** +- **待审批**: 变更请求已提交,等待审批人处理 +- **已批准**: 审批人已批准变更请求 +- **已拒绝**: 审批人拒绝了变更请求 +- **已撤销**: 发起人主动撤销变更请求 +- **已实施**: 批准的变更已在目标系统中实施 +- **已关闭**: 变更流程已完成或终止 + +状态转换由系统服务组件控制,当用户执行相应操作时触发状态变更。系统通过updateTime字段记录每个状态变更的时间戳,实现完整的审计跟踪。 + +## 审计日志 + +DataVines系统提供了完整的审计日志功能,用于记录所有变更审批操作。审计日志的主要特点包括: + +1. **操作记录**: 记录所有变更请求的创建、修改、审批和实施操作 +2. **时间戳**: 使用LocalDateTime类型精确记录操作时间 +3. **操作人**: 记录执行操作的用户ID +4. **变更详情**: 记录变更前后的值(changeBefore和changeAfter字段) + +审计日志通过CatalogSchemaChange实体的以下字段实现: +- `updateBy`: 记录操作执行者的用户ID +- `updateTime`: 记录操作发生的时间 +- `changeBefore`和`changeAfter`: 记录变更前后的值,便于审计对比 + +系统还提供了分页查询接口,支持按实体UUID查询变更历史,便于审计和追溯。 + +**审计日志来源** +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java#L30-L70) +- [CatalogSchemaChangeService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogSchemaChangeService.java#L25-L30) +- [CatalogSchemaChangeServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogSchemaChangeServiceImpl.java#L30-L47) + +## 超时处理与自动通过策略 + +虽然在提供的代码中没有直接体现超时处理和自动通过策略的实现,但基于系统设计模式,可以推断出可能的配置选项: + +1. **审批超时配置**: 系统可能支持为审批流程配置超时时间,当审批人在指定时间内未处理请求时,触发超时处理机制 +2. **自动通过策略**: 对于低风险的变更类型,系统可能支持配置自动通过规则,减少审批负担 +3. **通知提醒**: 在接近超时时间时,系统可能自动发送提醒通知给审批人 + +这些策略的配置可能通过系统配置服务或工作空间级别的设置进行管理,与具体的变更类型(SchemaChangeType)相关联。 + +## 常见问题解决 + +### 审批人配置错误 + +当出现审批人配置错误时,可以采取以下措施: +1. 检查用户角色和权限设置,确保审批人具有相应的审批权限 +2. 验证工作空间或项目的审批链配置 +3. 检查变更类型与审批规则的匹配关系 + +### 审批状态不一致 + +当出现审批状态不一致问题时,建议: +1. 检查数据库中CatalogSchemaChange记录的完整性 +2. 验证updateTime时间戳的顺序是否合理 +3. 确认变更流程的状态转换逻辑是否正确执行 + +### 变更历史查询问题 + +当无法正确查询变更历史时: +1. 确认entityUuid和parentUuid的查询条件是否正确 +2. 检查分页参数(pageNumber和pageSize)的设置 +3. 验证orderByDesc(updateTime)排序是否正常工作 + +**常见问题来源** +- [CatalogSchemaChangeServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogSchemaChangeServiceImpl.java#L34-L46) +- [CatalogSchemaChangeMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogSchemaChangeMapper.java#L1-L26) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\275\261\345\223\215\345\210\206\346\236\220.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\275\261\345\223\215\345\210\206\346\236\220.md" new file mode 100644 index 00000000..8d1f932f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\345\217\230\346\233\264\347\233\221\346\216\247/\345\275\261\345\223\215\345\210\206\346\236\220.md" @@ -0,0 +1,217 @@ +# 影响分析 + + +**本文档引用的文件** +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) +- [EntityRelType.java](file://datavines-common/src/main/java/io/datavines/common/enums/EntityRelType.java) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [CatalogEntityRelService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityRelService.java) +- [CatalogEntityRelServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityRelServiceImpl.java) +- [CatalogEntityRelMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityRelMapper.java) +- [JobQualityReportService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobQualityReportService.java) +- [JobQualityReportServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobQualityReportServiceImpl.java) +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) +- [CatalogTaskScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/CatalogTaskScheduleJob.java) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档详细阐述了DataVines中变更影响分析的实现机制。通过分析CatalogEntityRel关系表构建数据血缘图谱,说明变更对下游数据表、数据质量任务等的影响范围。文档涵盖影响分析的触发时机和执行流程,包括实时分析和批量分析两种模式。同时,阐述影响严重程度的评估标准和可视化展示方式,提供影响分析结果的导出和报告功能说明,并解决常见问题如血缘关系不完整、影响范围误判等。 + +## 项目结构 +DataVines项目结构清晰,主要模块包括datavines-server、datavines-connector、datavines-metric等。影响分析功能主要集中在datavines-server模块的catalog相关实体和服务中,通过CatalogEntityRel表存储实体间的上下游关系,构建数据血缘图谱。 + +```mermaid +graph TD +subgraph "前端" +UI[用户界面] +end +subgraph "后端" +Server[datavines-server] +Connector[datavines-connector] +Metric[datavines-metric] +end +UI --> Server +Server --> Connector +Server --> Metric +``` + +**图表来源** +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) +- [EntityRelType.java](file://datavines-common/src/main/java/io/datavines/common/enums/EntityRelType.java) + +**章节来源** +- [datavines-server](file://datavines-server) +- [datavines-connector](file://datavines-connector) +- [datavines-metric](file://datavines-metric) + +## 核心组件 +影响分析的核心组件包括CatalogEntityRel实体、CatalogEntityRelService服务以及相关的Mapper组件。这些组件共同协作,实现数据血缘关系的存储、查询和分析功能。 + +**章节来源** +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) +- [CatalogEntityRelService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityRelService.java) +- [CatalogEntityRelMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityRelMapper.java) + +## 架构概述 +DataVines的影响分析功能基于数据血缘图谱实现。通过CatalogEntityRel表存储实体间的上下游关系,系统能够分析变更对下游数据表、数据质量任务等的影响范围。影响分析的触发时机包括实时分析和批量分析两种模式。 + +```mermaid +graph TB +subgraph "数据源" +DataSource[数据源] +end +subgraph "元数据管理" +Catalog[元数据目录] +EntityRel[实体关系] +end +subgraph "影响分析" +ImpactAnalysis[影响分析] +Report[报告生成] +end +DataSource --> Catalog +Catalog --> EntityRel +EntityRel --> ImpactAnalysis +ImpactAnalysis --> Report +``` + +**图表来源** +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) +- [JobQualityReportService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobQualityReportService.java) + +## 详细组件分析 + +### CatalogEntityRel 分析 +CatalogEntityRel组件负责存储和管理实体间的上下游关系。通过entity1_uuid和entity2_uuid字段标识两个实体,type字段表示关系类型(上游、下游、父子等)。 + +#### 类图 +```mermaid +classDiagram +class CatalogEntityRel { ++Long id ++String entity1Uuid ++String entity2Uuid ++String type ++Long updateBy ++LocalDateTime updateTime +} +class EntityRelType { ++int code ++String description ++static EntityRelType of(String relType) +} +CatalogEntityRel --> EntityRelType : "引用" +``` + +**图表来源** +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) +- [EntityRelType.java](file://datavines-common/src/main/java/io/datavines/common/enums/EntityRelType.java) + +**章节来源** +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) +- [EntityRelType.java](file://datavines-common/src/main/java/io/datavines/common/enums/EntityRelType.java) + +### 影响分析执行流程 +影响分析的执行流程包括实时分析和批量分析两种模式。实时分析在数据变更时立即触发,批量分析则按预定时间调度执行。 + +#### 序列图 +```mermaid +sequenceDiagram +participant User as "用户" +participant Server as "服务器" +participant Service as "服务" +participant Mapper as "Mapper" +participant DB as "数据库" +User->>Server : 触发影响分析 +Server->>Service : 调用影响分析服务 +Service->>Mapper : 查询实体关系 +Mapper->>DB : 执行SQL查询 +DB-->>Mapper : 返回查询结果 +Mapper-->>Service : 返回实体关系 +Service->>Server : 返回影响分析结果 +Server-->>User : 显示影响分析结果 +``` + +**图表来源** +- [CatalogEntityRelService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityRelService.java) +- [CatalogEntityRelMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityRelMapper.java) + +**章节来源** +- [CatalogEntityRelService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityRelService.java) +- [CatalogEntityRelMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityRelMapper.java) + +### 数据血缘图谱构建 +数据血缘图谱的构建基于CatalogEntityRel表,通过递归查询上下游关系,形成完整的数据血缘网络。 + +#### 流程图 +```mermaid +flowchart TD +Start([开始]) --> QueryDB["查询CatalogEntityRel表"] +QueryDB --> ProcessResult["处理查询结果"] +ProcessResult --> BuildGraph["构建数据血缘图谱"] +BuildGraph --> AnalyzeImpact["分析变更影响"] +AnalyzeImpact --> GenerateReport["生成影响分析报告"] +GenerateReport --> End([结束]) +``` + +**图表来源** +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) +- [JobQualityReportService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobQualityReportService.java) + +**章节来源** +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) +- [JobQualityReportService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobQualityReportService.java) + +## 依赖分析 +影响分析功能依赖于多个组件和服务,包括CatalogEntityRelService、JobQualityReportService等。这些组件通过Spring框架进行依赖注入,确保系统的松耦合和高内聚。 + +```mermaid +graph TD +CatalogEntityRelService --> CatalogEntityRelMapper +CatalogEntityRelMapper --> DB[(数据库)] +JobQualityReportService --> JobExecutionResultMapper +JobExecutionResultMapper --> DB +CatalogTaskScheduleJob --> CatalogEntityRelService +DataQualityScheduleJob --> JobQualityReportService +``` + +**图表来源** +- [CatalogEntityRelService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityRelService.java) +- [JobQualityReportService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobQualityReportService.java) +- [CatalogTaskScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/CatalogTaskScheduleJob.java) +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) + +**章节来源** +- [CatalogEntityRelService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityRelService.java) +- [JobQualityReportService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobQualityReportService.java) +- [CatalogTaskScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/CatalogTaskScheduleJob.java) +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) + +## 性能考虑 +影响分析功能在处理大规模数据血缘关系时,需要考虑查询性能和内存占用。建议对CatalogEntityRel表的常用查询字段建立索引,并合理设置查询缓存。 + +## 故障排除指南 +### 血缘关系不完整 +当发现血缘关系不完整时,应检查数据源连接配置和元数据抓取任务是否正常执行。 + +**章节来源** +- [CatalogTaskScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/CatalogTaskScheduleJob.java) + +### 影响范围误判 +影响范围误判可能由于实体关系数据不准确导致,应核对CatalogEntityRel表中的关系数据。 + +**章节来源** +- [CatalogEntityRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java) + +## 结论 +DataVines的影响分析功能通过CatalogEntityRel关系表构建数据血缘图谱,能够有效分析变更对下游数据表、数据质量任务等的影响范围。系统支持实时分析和批量分析两种模式,提供完整的影响分析报告和可视化展示。通过合理的性能优化和故障排除,确保影响分析功能的准确性和高效性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\346\225\260\346\215\256\347\233\256\345\275\225.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\346\225\260\346\215\256\347\233\256\345\275\225.md" new file mode 100644 index 00000000..8f0c6aa3 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\346\225\260\346\215\256\347\233\256\345\275\225.md" @@ -0,0 +1,275 @@ +# 数据目录 + + +**本文档引用的文件** +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java) +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java) +- [CatalogTag.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java) +- [CatalogTagCategory.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTagCategory.java) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [CatalogTagService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagService.java) +- [CatalogTagCategoryService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagCategoryService.java) +- [CatalogMetaDataFetchExecutor.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutor.java) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [README.zh-CN.md](file://README.zh-CN.md) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 + +DataVines 是一个一站式开源数据可观测性平台,提供元数据管理、数据概览报告、数据质量管理、数据分布查询、数据趋势洞察等核心能力。数据目录是 DataVines 的核心功能之一,旨在帮助用户全面了解和管理其数据资产。通过定时获取数据源元数据、监听元数据变更以及支持元数据的标签管理,数据目录为数据发现、数据血缘和数据治理提供了坚实的基础。 + +## 项目结构 + +DataVines 的项目结构清晰地划分了不同的模块,每个模块负责特定的功能。数据目录相关的代码主要位于 `datavines-server` 模块中,特别是 `repository/entity/catalog` 和 `api/controller` 目录下。这些目录包含了数据目录的核心实体定义、服务接口和控制器。 + +```mermaid +graph TD +subgraph "datavines-server" +subgraph "repository" +subgraph "entity" +subgraph "catalog" +CatalogEntityInstance +CatalogEntityDefinition +CatalogTag +CatalogTagCategory +end +end +subgraph "service" +CatalogEntityInstanceService +CatalogTagService +CatalogTagCategoryService +end +end +subgraph "api" +subgraph "controller" +CatalogController +CatalogTagController +end +end +end +``` + +**图表来源** +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java) +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java) +- [CatalogTag.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java) +- [CatalogTagCategory.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTagCategory.java) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [CatalogTagService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagService.java) +- [CatalogTagCategoryService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagCategoryService.java) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) + +## 核心组件 + +### CatalogEntityInstance + +`CatalogEntityInstance` 类表示数据目录中的具体实例,如数据库、表或列。它包含了实例的基本信息,如 UUID、数据源 ID、类型、完全限定名称、显示名称、描述、属性、所有者、版本、状态、创建时间和更新时间。 + +**部分来源** +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java#L35-L78) + +### CatalogEntityDefinition + +`CatalogEntityDefinition` 类表示数据目录中的实体定义,用于描述实体的元数据。它包含了定义的基本信息,如 UUID、名称、描述、属性、父级 UUID、创建者、创建时间、更新者和更新时间。 + +**部分来源** +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java#L35-L63) + +### CatalogTag + +`CatalogTag` 类表示数据目录中的标签,用于对数据资产进行分类和标记。它包含了标签的基本信息,如 UUID、类别 UUID、名称、创建者、创建时间、更新者和更新时间。 + +**部分来源** +- [CatalogTag.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java#L38-L59) + +### CatalogTagCategory + +`CatalogTagCategory` 类表示数据目录中的标签类别,用于组织和管理标签。它包含了类别的基本信息,如 UUID、名称、工作空间 ID、创建者、创建时间、更新者和更新时间。 + +**部分来源** +- [CatalogTagCategory.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTagCategory.java#L38-L59) + +## 架构概述 + +DataVines 的数据目录系统采用分层架构设计,主要包括以下几个层次: + +1. **API 层**:提供 RESTful API 接口,供前端 UI 和外部系统调用。 +2. **服务层**:实现业务逻辑,处理来自 API 层的请求,并调用数据访问层进行数据操作。 +3. **数据访问层**:负责与数据库交互,执行 CRUD 操作。 +4. **元数据采集层**:定时从数据源获取元数据,并更新到数据目录中。 + +```mermaid +graph TD +subgraph "前端/UI" +UI[用户界面] +end +subgraph "API 层" +API[API 接口] +end +subgraph "服务层" +Service[服务实现] +end +subgraph "数据访问层" +DAO[数据访问对象] +end +subgraph "数据库" +DB[(数据库)] +end +subgraph "元数据采集层" +MetadataFetcher[元数据采集器] +end +UI --> API +API --> Service +Service --> DAO +DAO --> DB +MetadataFetcher --> DB +``` + +**图表来源** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [CatalogTagService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagService.java) +- [CatalogTagCategoryService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagCategoryService.java) +- [CatalogEntityInstance.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java) +- [CatalogEntityDefinition.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java) +- [CatalogTag.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java) +- [CatalogTagCategory.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTagCategory.java) + +## 详细组件分析 + +### 元数据采集 + +元数据采集是数据目录的核心功能之一,通过定时任务从数据源获取最新的元数据信息。`CatalogMetaDataFetchExecutor` 接口定义了元数据采集的执行方法,具体的实现类 `CatalogMetaDataFetchExecutorImpl` 负责执行实际的采集任务。 + +```mermaid +classDiagram +class CatalogMetaDataFetchExecutor { +<> ++execute() void +} +class CatalogMetaDataFetchExecutorImpl { ++execute() void +} +CatalogMetaDataFetchExecutor <|-- CatalogMetaDataFetchExecutorImpl +``` + +**图表来源** +- [CatalogMetaDataFetchExecutor.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutor.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) + +### 标签管理 + +标签管理功能允许用户为数据资产添加标签,以便更好地组织和分类。`CatalogTagController` 提供了创建、删除、查询标签及其类别的 API 接口。`CatalogTagService` 和 `CatalogTagCategoryService` 分别实现了标签和标签类别的业务逻辑。 + +#### 创建标签类别 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "CatalogTagController" +participant Service as "CatalogTagCategoryService" +participant Mapper as "CatalogTagCategoryMapper" +Client->>Controller : POST /api/catalog/tag/category +Controller->>Service : create(TagCategoryCreate) +Service->>Mapper : insert(CatalogTagCategory) +Mapper-->>Service : 返回插入结果 +Service-->>Controller : 返回创建结果 +Controller-->>Client : 返回响应 +``` + +**图表来源** +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java#L47-L51) +- [CatalogTagCategoryService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagCategoryService.java#L27-L31) +- [CatalogTagCategoryMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogTagCategoryMapper.java) + +#### 为实体添加标签 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "CatalogTagController" +participant Service as "CatalogTagService" +participant Mapper as "CatalogTagMapper" +Client->>Controller : POST /api/catalog/tag/entity-tag +Controller->>Service : addEntityTagRel(entityUUID, tagUUID) +Service->>Mapper : insert(EntityTagRel) +Mapper-->>Service : 返回插入结果 +Service-->>Controller : 返回添加结果 +Controller-->>Client : 返回响应 +``` + +**图表来源** +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java#L95-L99) +- [CatalogTagService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagService.java#L37-L39) +- [CatalogTagMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogTagMapper.java) + +## 依赖分析 + +数据目录系统的各个组件之间存在紧密的依赖关系。`CatalogController` 依赖于 `CatalogEntityInstanceService` 和 `CatalogSchemaChangeService` 等服务来处理业务逻辑。`CatalogTagController` 依赖于 `CatalogTagService` 和 `CatalogTagCategoryService` 来管理标签和标签类别。 + +```mermaid +graph TD +CatalogController --> CatalogEntityInstanceService +CatalogController --> CatalogSchemaChangeService +CatalogTagController --> CatalogTagService +CatalogTagController --> CatalogTagCategoryService +CatalogEntityInstanceService --> CatalogEntityInstanceMapper +CatalogTagService --> CatalogTagMapper +CatalogTagCategoryService --> CatalogTagCategoryMapper +``` + +**图表来源** +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java#L51-L58) +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java#L41-L45) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [CatalogTagService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagService.java) +- [CatalogTagCategoryService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagCategoryService.java) + +## 性能考虑 + +为了确保数据目录系统的高性能,建议采取以下措施: + +1. **优化数据库查询**:使用索引和缓存来加速频繁的查询操作。 +2. **异步处理**:将耗时的操作(如元数据采集)放入后台任务中异步执行,避免阻塞主线程。 +3. **分页查询**:对于大量数据的查询,使用分页机制减少单次请求的数据量。 +4. **定期清理**:定期清理不再使用的元数据和标签,保持数据库的整洁。 + +## 故障排除指南 + +### 元数据同步延迟 + +如果发现元数据同步有延迟,可以检查以下几点: + +1. **任务调度**:确认元数据采集任务是否正常调度和执行。 +2. **网络连接**:检查数据源的网络连接是否稳定。 +3. **资源限制**:查看服务器资源(CPU、内存)是否充足。 + +### 标签冲突 + +如果遇到标签冲突问题,可以采取以下措施: + +1. **唯一性校验**:在创建标签时增加唯一性校验,防止重复创建。 +2. **事务管理**:使用数据库事务确保标签创建和关联操作的原子性。 + +**部分来源** +- [CatalogTagCategoryServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagCategoryServiceImpl.java#L48-L50) +- [CatalogTagServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java) + +## 结论 + +DataVines 的数据目录系统通过元数据采集、实体定义、实例管理、标签分类和变更监控等功能,为用户提供了一个全面的数据资产管理平台。通过合理的架构设计和高效的性能优化,该系统能够满足大规模数据环境下的需求。希望本文档能帮助您更好地理解和使用 DataVines 的数据目录功能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\346\240\207\347\255\276\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\346\240\207\347\255\276\347\256\241\347\220\206.md" new file mode 100644 index 00000000..93adca86 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\347\233\256\345\275\225/\346\240\207\347\255\276\347\256\241\347\220\206.md" @@ -0,0 +1,219 @@ +# 标签管理 + + +**本文档中引用的文件** +- [CatalogTag.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java) +- [CatalogTagCategory.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTagCategory.java) +- [CatalogEntityTagRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityTagRel.java) +- [CatalogTagServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java) +- [CatalogTagCategoryServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagCategoryServiceImpl.java) +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [TagCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/catalog/tag/TagCreate.java) +- [TagCategoryCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/catalog/tag/TagCategoryCreate.java) +- [CatalogTagVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/catalog/CatalogTagVO.java) +- [CatalogTagMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogTagMapper.java) +- [CatalogEntityTagRelMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityTagRelMapper.java) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +DataVines中的标签管理功能为数据资产提供了灵活的分类和组织机制。通过标签系统,用户可以对数据实体进行分类、打标签,并基于标签进行搜索和过滤。本文档详细阐述了标签系统的架构设计、核心实体、操作接口以及使用方法。 + +## 项目结构 +标签管理功能主要位于`datavines-server`模块中,涉及实体定义、服务实现、控制器接口和数据库映射等多个层次。整体结构遵循典型的分层架构模式,包括控制器层、服务层、数据访问层和实体层。 + +```mermaid +graph TB +subgraph "Controller" +A[CatalogTagController] +end +subgraph "Service" +B[CatalogTagService] +C[CatalogTagCategoryService] +end +subgraph "Mapper" +D[CatalogTagMapper] +E[CatalogEntityTagRelMapper] +end +subgraph "Entity" +F[CatalogTag] +G[CatalogTagCategory] +H[CatalogEntityTagRel] +end +A --> B +A --> C +B --> D +B --> E +C --> D +D --> F +E --> H +B --> F +C --> G +``` + +**图示来源** +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogTagService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagService.java) +- [CatalogTagMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogTagMapper.java) +- [CatalogTag.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java) + +**节来源** +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogTagService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogTagService.java) + +## 核心组件 +标签管理系统的核心组件包括标签实体(CatalogTag)、标签分类实体(CatalogTagCategory)和标签与实体的关联关系(CatalogEntityTagRel)。这些组件共同构成了标签系统的数据模型。 + +**节来源** +- [CatalogTag.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java) +- [CatalogTagCategory.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTagCategory.java) +- [CatalogEntityTagRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityTagRel.java) + +## 架构概述 +标签系统的架构采用典型的三层模式:表现层(Controller)、业务逻辑层(Service)和数据访问层(Mapper)。表现层负责接收HTTP请求并返回响应;业务逻辑层处理具体的业务规则和流程;数据访问层负责与数据库交互。 + +```mermaid +graph TD +Client --> |HTTP Request| Controller +Controller --> |调用| Service +Service --> |调用| Mapper +Mapper --> |SQL查询| Database +Database --> |结果| Mapper +Mapper --> |数据对象| Service +Service --> |业务结果| Controller +Controller --> |JSON响应| Client +``` + +**图示来源** +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogTagServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java) +- [CatalogTagMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogTagMapper.java) + +## 详细组件分析 + +### 标签实体分析 +`CatalogTag`实体表示一个具体的标签,包含标签名称、所属分类、创建和更新信息等属性。每个标签通过UUID唯一标识,并与特定的标签分类关联。 + +```mermaid +classDiagram +class CatalogTag { ++Long id ++String uuid ++String categoryUuid ++String name ++Long createBy ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +class CatalogTagCategory { ++Long id ++String uuid ++String name ++Long workspaceId ++Long createBy ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +class CatalogEntityTagRel { ++Long id ++String entityUuid ++String tagUuid ++Long createBy ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +CatalogTag --> CatalogTagCategory : "属于" +CatalogEntityTagRel --> CatalogTag : "引用" +``` + +**图示来源** +- [CatalogTag.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java) +- [CatalogTagCategory.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTagCategory.java) +- [CatalogEntityTagRel.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityTagRel.java) + +**节来源** +- [CatalogTag.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java) +- [CatalogTagCategory.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTagCategory.java) + +### 标签操作流程分析 +标签的创建、删除和关联操作通过REST API暴露,客户端可以通过HTTP请求执行这些操作。以下序列图展示了创建标签的完整流程。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "CatalogTagController" +participant Service as "CatalogTagService" +participant Mapper as "CatalogTagMapper" +participant Database as "数据库" +Client->>Controller : POST /api/v1/catalog/tag +Controller->>Service : create(TagCreate) +Service->>Service : isExist(name) +alt 标签已存在 +Service-->>Controller : 抛出异常 +else 标签不存在 +Service->>Service : 创建CatalogTag对象 +Service->>Mapper : insert(catalogTag) +Mapper->>Database : INSERT INTO dv_catalog_tag +Database-->>Mapper : 返回结果 +Mapper-->>Service : 返回结果 +Service-->>Controller : 返回标签ID +end +Controller-->>Client : 返回标签ID +``` + +**图示来源** +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogTagServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java) +- [CatalogTagMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogTagMapper.java) + +**节来源** +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogTagServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java) + +## 依赖分析 +标签系统依赖于MyBatis Plus框架进行数据库操作,使用Lombok简化实体类代码,并通过Spring框架管理组件生命周期。系统内部各组件之间存在明确的依赖关系,控制器依赖服务,服务依赖映射器。 + +```mermaid +graph TD +CatalogTagController --> CatalogTagService +CatalogTagController --> CatalogTagCategoryService +CatalogTagService --> CatalogTagMapper +CatalogTagService --> CatalogEntityTagRelService +CatalogEntityTagRelService --> CatalogEntityTagRelMapper +CatalogTagCategoryService --> CatalogTagCategoryMapper +``` + +**图示来源** +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogTagServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java) +- [CatalogTagCategoryServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagCategoryServiceImpl.java) + +**节来源** +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogTagServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java) + +## 性能考虑 +标签系统的性能主要受数据库查询效率影响。为提高查询性能,建议在`dv_catalog_tag`表的`category_uuid`字段和`dv_catalog_entity_tag_rel`表的`entity_uuid`字段上建立索引。此外,对于频繁访问的标签数据,可以考虑引入缓存机制。 + +## 故障排除指南 +常见问题包括标签创建失败(名称重复)、标签关联失败(权限不足)等。当遇到问题时,首先检查请求参数是否符合规范,然后查看服务日志以获取详细的错误信息。对于数据库相关的问题,需要检查表结构和索引是否正确。 + +**节来源** +- [CatalogTagServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java) +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) + +## 结论 +DataVines的标签管理系统提供了一套完整的标签管理功能,支持标签分类、标签创建、标签关联和标签查询等操作。系统架构清晰,组件职责明确,便于维护和扩展。通过合理使用标签,用户可以更高效地组织和管理数据资产。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\346\211\247\350\241\214\345\271\263\345\217\260.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\346\211\247\350\241\214\345\271\263\345\217\260.md" new file mode 100644 index 00000000..c91c5bde --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\346\211\247\350\241\214\345\271\263\345\217\260.md" @@ -0,0 +1,361 @@ +# 执行平台 + + +**本文档中引用的文件** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java) +- [io.datavines.engine.api.engine.EngineExecutor](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/resources/META-INF/plugins/io.datavines.engine.api.engine.EngineExecutor) +- [io.datavines.engine.api.env.RuntimeEnvironment](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/resources/META-INF/plugins/io.datavines.engine.api.env.RuntimeEnvironment) + + +## 目录 +1. [简介](#简介) +2. [执行平台架构](#执行平台架构) +3. [核心组件分析](#核心组件分析) +4. [平台技术对比](#平台技术对比) +5. [平台选择与配置](#平台选择与配置) + +## 简介 +DataVines支持三种执行平台:Spark、Flink和Local,每种平台针对不同的数据处理场景进行了优化。本文档详细说明各平台的技术架构、适用场景和性能特点,帮助用户根据业务需求选择合适的执行平台。 + +## 执行平台架构 + +```mermaid +graph TD +subgraph "执行平台" +Spark[Spark平台] +Flink[Flink平台] +Local[Local平台] +end +subgraph "核心接口" +EngineExecutor[EngineExecutor] +RuntimeEnvironment[RuntimeEnvironment] +Execution[Execution] +end +Spark --> EngineExecutor +Flink --> EngineExecutor +Local --> EngineExecutor +Spark --> RuntimeEnvironment +Flink --> RuntimeEnvironment +Local --> RuntimeEnvironment +Spark --> Execution +Flink --> Execution +Local --> Execution +EngineExecutor --> |实现| SparkEngineExecutor[SparkEngineExecutor] +EngineExecutor --> |实现| FlinkEngineExecutor[FlinkEngineExecutor] +EngineExecutor --> |实现| LocalEngineExecutor[LocalEngineExecutor] +RuntimeEnvironment --> |实现| SparkRuntimeEnvironment[SparkRuntimeEnvironment] +RuntimeEnvironment --> |实现| FlinkRuntimeEnvironment[FlinkRuntimeEnvironment] +RuntimeEnvironment --> |实现| LocalRuntimeEnvironment[LocalRuntimeEnvironment] +Execution --> |实现| SparkBatchExecution[SparkBatchExecution] +Execution --> |实现| FlinkStreamExecution[FlinkStreamExecution] +Execution --> |实现| LocalExecution[LocalExecution] +``` + +**图源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + +## 核心组件分析 + +### 执行引擎接口 + +DataVines的执行平台基于统一的接口设计,通过SPI机制实现插件化扩展。核心接口包括`EngineExecutor`、`RuntimeEnvironment`和`Execution`。 + +```mermaid +classDiagram +class EngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++isCancel() boolean ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest +} +class RuntimeEnvironment { ++prepare() void ++getExecution() Execution +} +class Execution { ++execute(SR[], TF[], SK[]) void ++stop() void ++prepare() void +} +class LocalEngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void +} +class FlinkEngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void +} +class SparkEngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void +} +EngineExecutor <|-- LocalEngineExecutor +EngineExecutor <|-- FlinkEngineExecutor +EngineExecutor <|-- SparkEngineExecutor +RuntimeEnvironment <|-- FlinkRuntimeEnvironment +RuntimeEnvironment <|-- SparkRuntimeEnvironment +RuntimeEnvironment <|-- LocalRuntimeEnvironment +Execution <|-- FlinkStreamExecution +Execution <|-- SparkBatchExecution +Execution <|-- LocalExecution +``` + +**图源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + +**本节源码** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java#L23-L28) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java#L23-L30) + +### Spark平台 + +Spark平台提供强大的分布式计算能力,适用于大规模数据处理场景。通过`SparkEngineExecutor`实现`EngineExecutor`接口,利用Spark的批处理能力执行数据质量检查任务。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant SparkEngineExecutor as "SparkEngineExecutor" +participant SparkRuntimeEnvironment as "SparkRuntimeEnvironment" +participant SparkBatchExecution as "SparkBatchExecution" +Client->>SparkEngineExecutor : init() +SparkEngineExecutor->>SparkEngineExecutor : 初始化执行请求 +SparkEngineExecutor->>SparkEngineExecutor : 设置日志 +Client->>SparkEngineExecutor : execute() +SparkEngineExecutor->>SparkRuntimeEnvironment : 创建运行时环境 +SparkRuntimeEnvironment->>SparkRuntimeEnvironment : 准备Spark上下文 +SparkRuntimeEnvironment->>SparkBatchExecution : 获取执行实例 +SparkBatchExecution->>SparkBatchExecution : 执行数据源、转换、接收器 +SparkBatchExecution-->>SparkEngineExecutor : 返回执行结果 +SparkEngineExecutor-->>Client : 完成执行 +``` + +**图源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) +- [SparkBatchExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/batch/SparkBatchExecution.java) + +### Flink平台 + +Flink平台具有流批一体的特性,适用于实时数据质量检查。通过`FlinkEngineExecutor`实现`EngineExecutor`接口,支持流式和批处理模式。 + +```mermaid +flowchart TD +Start([Flink执行开始]) --> Init["初始化执行请求"] +Init --> CreateEnv["创建Flink运行时环境"] +CreateEnv --> CheckMode{"检查执行模式"} +CheckMode --> |流模式| CreateStream["创建StreamExecutionEnvironment"] +CheckMode --> |批模式| CreateBatch["设置BATCH运行模式"] +CreateStream --> CreateTableEnv["创建StreamTableEnvironment"] +CreateBatch --> CreateTableEnv +CreateTableEnv --> ExecuteJob["执行数据质量检查作业"] +ExecuteJob --> Monitor["监控作业状态"] +Monitor --> Complete["作业完成"] +Complete --> Cleanup["清理资源"] +Cleanup --> End([执行结束]) +``` + +**图源** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java#L64-L78) +- [FlinkStreamExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/stream/FlinkStreamExecution.java) + +### Local平台 + +Local平台具有轻量级特性,适用于开发测试和小规模数据验证。通过`LocalEngineExecutor`实现`EngineExecutor`接口,在本地JVM中执行任务。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant LocalEngineExecutor as "LocalEngineExecutor" +participant LocalRuntimeEnvironment as "LocalRuntimeEnvironment" +participant LocalExecution as "LocalExecution" +Client->>LocalEngineExecutor : init() +LocalEngineExecutor->>LocalEngineExecutor : 初始化执行请求 +LocalEngineExecutor->>LocalEngineExecutor : 设置线程名称 +Client->>LocalEngineExecutor : execute() +LocalEngineExecutor->>LocalRuntimeEnvironment : 创建本地引导程序 +LocalRuntimeEnvironment->>LocalRuntimeEnvironment : 准备执行环境 +LocalRuntimeEnvironment->>LocalExecution : 获取执行实例 +LocalExecution->>LocalExecution : 执行本地数据处理 +LocalExecution-->>LocalEngineExecutor : 返回执行结果 +LocalEngineExecutor-->>Client : 完成执行 +``` + +**图源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L27-L57) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) + +## 平台技术对比 + +```mermaid +erDiagram +PLATFORM ||--o{ PERFORMANCE : has +PLATFORM { +string name PK +string description +string use_case +} +PERFORMANCE }|--|| PLATFORM : belongs_to +PERFORMANCE { +string platform PK +float throughput +float latency +float resource_utilization +string scalability +} +PLATFORM ||--o{ CONFIGURATION : has +CONFIGURATION }|--|| PLATFORM : belongs_to +CONFIGURATION { +string platform PK +string initialization_process +string runtime_config +string resource_management +} +PLATFORM { +"Spark" "分布式计算,大规模数据处理" +"Flink" "流批一体,实时数据质量检查" +"Local" "轻量级,开发测试" +} +PERFORMANCE { +"Spark" 10000 100 0.8 "高" +"Flink" 5000 10 0.6 "中" +"Local" 100 1 0.1 "低" +} +CONFIGURATION { +"Spark" "初始化Spark上下文" "配置Spark参数" "YARN资源管理" +"Flink" "初始化Flink环境" "配置流/批模式" "Flink原生资源管理" +"Local" "本地JVM初始化" "简单配置" "JVM内存管理" +} +``` + +**图源** +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L24-L72) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) + +## 平台选择与配置 + +### 平台初始化过程 + +各平台的初始化过程遵循统一的接口规范,但具体实现有所不同: + +```mermaid +flowchart TD +A[开始初始化] --> B{选择平台} +B --> |Spark| C[创建SparkContext] +B --> |Flink| D[创建StreamExecutionEnvironment] +B --> |Local| E[创建本地执行环境] +C --> F[配置Spark参数] +D --> G[配置Flink参数] +E --> H[配置本地参数] +F --> I[准备执行环境] +G --> I +H --> I +I --> J[返回运行时环境] +J --> K[结束初始化] +``` + +**图源** +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java#L70-L78) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L31-L38) + +### 运行时环境配置 + +运行时环境配置是各平台的关键差异点,决定了平台的性能和资源利用方式。 + +```mermaid +classDiagram +class SparkRuntimeEnvironment { +-SparkConf conf +-JavaSparkContext context ++prepare() void ++getExecution() Execution +} +class FlinkRuntimeEnvironment { +-StreamExecutionEnvironment env +-StreamTableEnvironment tableEnv ++prepare() void ++getExecution() Execution +} +class LocalRuntimeEnvironment { ++prepare() void ++getExecution() Execution +} +SparkRuntimeEnvironment -->|使用| SparkConf +SparkRuntimeEnvironment -->|使用| JavaSparkContext +FlinkRuntimeEnvironment -->|使用| StreamExecutionEnvironment +FlinkRuntimeEnvironment -->|使用| StreamTableEnvironment +``` + +**图源** +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) + +### 资源管理机制 + +各平台的资源管理机制反映了其设计哲学和适用场景: + +```mermaid +graph TD +subgraph "资源管理" +SparkResourceManager["Spark资源管理
- YARN集成
- 动态资源分配
- 内存管理"] +FlinkResourceManager["Flink资源管理
- 原生资源管理
- Slot分配
- 内存管理"] +LocalResourceManager["Local资源管理
- JVM内存
- 单线程执行
- 无外部依赖"] +end +SparkResourceManager --> |适用于| LargeScale["大规模数据处理"] +FlinkResourceManager --> |适用于| RealTime["实时数据处理"] +LocalResourceManager --> |适用于| Development["开发测试"] +``` + +**图源** +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) + +### 平台选择指南 + +根据业务需求选择合适的执行平台是确保数据质量检查效率和成本效益的关键: + +```mermaid +flowchart TD +A[选择执行平台] --> B{数据规模} +B --> |大规模| C{处理模式} +B --> |小规模| D[选择Local平台] +C --> |批处理| E[选择Spark平台] +C --> |流处理| F[选择Flink平台] +D --> G[开发测试] +E --> H[数据仓库质量检查] +F --> I[实时数据监控] +G --> J[完成] +H --> J +I --> J +``` + +**本节源码** +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\346\211\247\350\241\214\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\346\211\247\350\241\214\351\205\215\347\275\256.md" new file mode 100644 index 00000000..aa3a74f2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\346\211\247\350\241\214\351\205\215\347\275\256.md" @@ -0,0 +1,259 @@ +# 执行配置 + + +**本文档中引用的文件** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [FlinkArgsUtils.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java) +- [SparkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [DataQualityJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataQualityJobParameter.java) +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [EngineConstants.java](file://datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [README.md](file://datavines-engine/README.md) + + +## 目录 +1. [引言](#引言) +2. [执行平台概述](#执行平台概述) +3. [Spark执行平台配置](#spark执行平台配置) +4. [Flink执行平台配置](#flink执行平台配置) +5. [Local执行平台配置](#local执行平台配置) +6. [执行环境初始化与运行时上下文管理](#执行环境初始化与运行时上下文管理) +7. [性能优化配置](#性能优化配置) +8. [执行平台选型建议](#执行平台选型建议) +9. [监控与日志配置](#监控与日志配置) +10. [故障转移与高可用性配置](#故障转移与高可用性配置) + +## 引言 +本文档全面介绍DataVines数据质量检查任务的执行环境配置。详细说明了Spark、Flink和Local三种执行平台的特点、适用场景和配置要求,为用户选择合适的执行平台提供指导。文档涵盖了资源分配、并行度设置、超时策略、重试机制等关键配置参数,并提供了性能优化建议和监控配置方案。 + +## 执行平台概述 +DataVines支持三种主要的执行平台:Spark、Flink和Local。每种平台都有其独特的特点和适用场景,用户可以根据数据量、实时性要求和资源可用性进行选择。 + +```mermaid +graph TD +A[执行平台] --> B[Spark] +A --> C[Flink] +A --> D[Local] +B --> E[批处理/流处理] +C --> F[流处理优先] +D --> G[单机测试] +``` + +**图源** +- [README.md](file://datavines-engine/README.md#L3-L14) + +## Spark执行平台配置 +Spark执行平台适用于大规模数据批处理场景,支持YARN集群部署模式。通过SparkEngineParameter类定义了详细的资源配置参数。 + +### 资源配置参数 +Spark执行平台的资源配置包括驱动程序和执行器的CPU核心数、内存大小以及执行器数量等关键参数。 + +**执行平台参数说明** +| 参数名称 | 描述 | 默认值 | +|---------|------|-------| +| programType | 程序类型 | 无 | +| deployMode | 部署模式 | 无 | +| driverCores | 驱动程序核心数 | 0 | +| driverMemory | 驱动程序内存 | 无 | +| numExecutors | 执行器数量 | 0 | +| executorCores | 每个执行器的核心数 | 0 | +| executorMemory | 每个执行器的内存 | 无 | +| others | 其他参数 | 无 | + +**节源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L26-L68) + +### 执行流程 +Spark引擎通过SparkEngineExecutor实现任务执行,构建spark-submit命令并提交到集群执行。 + +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant SparkEngineExecutor as Spark引擎执行器 +participant ShellCommandProcess as Shell命令处理器 +participant 集群 as YARN集群 +用户->>SparkEngineExecutor : 提交任务请求 +SparkEngineExecutor->>SparkEngineExecutor : 初始化配置 +SparkEngineExecutor->>SparkEngineExecutor : 构建spark-submit命令 +SparkEngineExecutor->>ShellCommandProcess : 执行命令 +ShellCommandProcess->>集群 : 提交Spark作业 +集群-->>ShellCommandProcess : 返回执行结果 +ShellCommandProcess-->>SparkEngineExecutor : 返回进程结果 +SparkEngineExecutor-->>用户 : 返回最终结果 +``` + +**图源** +- [SparkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L153) + +## Flink执行平台配置 +Flink执行平台专为流式数据处理设计,支持多种部署模式,包括yarn-session、yarn-per-job和yarn-application。 + +### 部署模式配置 +Flink支持多种部署模式,每种模式对应不同的命令行参数和执行方式。 + +**Flink部署模式** +| 模式 | 命令 | 特点 | +|------|------|------| +| yarn-session | run -t yarn-session | 会话模式,资源共享 | +| yarn-per-job | run -t yarn-per-job --detached | 每作业模式,资源隔离 | +| yarn-application | run-application -t yarn-application | 应用模式,完全独立 | +| local | run | 本地模式,单机执行 | + +**节源** +- [FlinkArgsUtils.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L26-L30) + +### 并行度配置 +Flink执行平台支持通过-p参数设置任务并行度,优化资源利用率和处理性能。 + +```mermaid +flowchart TD +A[开始] --> B[读取Flink参数] +B --> C{并行度>0?} +C --> |是| D[添加-p参数] +C --> |否| E[不设置并行度] +D --> F[构建完整命令] +E --> F +F --> G[执行任务] +``` + +**图源** +- [FlinkArgsUtils.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L67-L71) + +## Local执行平台配置 +Local执行平台适用于开发测试和小规模数据验证场景,直接在本地JVM中执行任务。 + +### 本地执行特点 +Local执行平台具有启动快速、配置简单的特点,适合调试和验证数据质量规则。 + +```mermaid +classDiagram +class LocalEngineExecutor { ++init(request, logger, configs) ++execute() ++after() ++cancel() ++getProcessResult() ++getTaskRequest() ++buildCommand() +} +class AbstractEngineExecutor { +<> +} +LocalEngineExecutor --|> AbstractEngineExecutor : 继承 +``` + +**图源** +- [LocalEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L27-L78) + +### 执行流程 +Local引擎直接调用LocalDataVinesBootstrap执行任务,无需外部集群支持。 + +**节源** +- [LocalEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L40-L47) + +## 执行环境初始化与运行时上下文管理 +执行环境的初始化过程包括配置加载、日志设置和执行器初始化等关键步骤。 + +### 初始化流程 +每种执行平台在执行任务前都需要进行初始化,设置线程名称、日志记录器和相关配置。 + +```mermaid +flowchart TD +A[开始初始化] --> B[设置线程日志名称] +B --> C[设置当前线程名称] +C --> D[保存任务请求] +D --> E[保存日志记录器] +E --> F[创建命令处理器] +F --> G[保存配置] +G --> H[完成初始化] +``` + +**节源** +- [SparkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L51-L61) +- [FlinkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L55-L68) +- [LocalEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L32-L38) + +## 性能优化配置 +通过合理的配置可以显著提升数据质量检查任务的执行性能。 + +### 数据分片策略 +根据数据源的特性配置合适的分片策略,提高并行处理能力。 + +### 缓存配置 +合理配置内存缓存,减少重复计算和I/O操作。 + +### 序列化方式 +选择高效的序列化方式,减少网络传输和内存占用。 + +**节源** +- [SparkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L126-L128) +- [FlinkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L109-L111) + +## 执行平台选型建议 +根据不同的业务场景和需求选择合适的执行平台。 + +### 选择因素 +| 因素 | Spark | Flink | Local | +|------|-------|-------|-------| +| 数据量 | 大规模 | 中到大规模 | 小规模 | +| 实时性 | 批处理 | 流处理 | 即时 | +| 资源要求 | 高 | 中高 | 低 | +| 复杂度 | 中 | 高 | 低 | + +### 适用场景 +- **Spark**: 适合大规模批处理任务,数据量大且对实时性要求不高的场景 +- **Flink**: 适合流式数据处理,需要低延迟和高吞吐量的场景 +- **Local**: 适合开发测试、规则验证和小规模数据检查 + +## 监控与日志配置 +完善的监控和日志配置有助于及时发现和解决问题。 + +### 日志记录 +所有执行平台都集成了统一的日志记录机制,便于问题排查和性能分析。 + +```mermaid +flowchart TD +A[任务执行] --> B[记录开始日志] +B --> C[执行核心逻辑] +C --> D{执行成功?} +D --> |是| E[记录成功日志] +D --> |否| F[记录错误日志] +E --> G[返回结果] +F --> H[抛出异常] +``` + +**节源** +- [SparkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L66-L71) +- [FlinkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L74-L81) + +## 故障转移与高可用性配置 +通过合理的配置实现任务的故障转移和高可用性。 + +### 重试机制 +配置适当的重试次数和间隔,提高任务的容错能力。 + +### 超时策略 +设置合理的超时时间,避免任务长时间占用资源。 + +### 故障恢复 +Flink平台支持通过cancel方法终止任务并清理YARN应用。 + +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant FlinkEngineExecutor as Flink引擎执行器 +participant YarnUtils as YARN工具 +用户->>FlinkEngineExecutor : 请求取消任务 +FlinkEngineExecutor->>FlinkEngineExecutor : 设置取消标志 +FlinkEngineExecutor->>FlinkEngineExecutor : 取消命令处理器 +FlinkEngineExecutor->>YarnUtils : 获取YARN应用ID +YarnUtils-->>FlinkEngineExecutor : 返回应用ID +FlinkEngineExecutor->>FlinkEngineExecutor : 构建kill命令 +FlinkEngineExecutor->>操作系统 : 执行kill命令 +``` + +**节源** +- [FlinkEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L143-L167) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\350\260\203\345\272\246\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\350\260\203\345\272\246\347\255\226\347\225\245.md" new file mode 100644 index 00000000..b128c840 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\350\260\203\345\272\246\347\255\226\347\225\245.md" @@ -0,0 +1,282 @@ +# 调度策略 + + +**本文档引用的文件** +- [TimeoutStrategy.java](file://datavines-common\src\main\java\io\datavines\common\enums\TimeoutStrategy.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java) +- [JobRunner.java](file://datavines-runner\src\main\java\io\datavines\runner\JobRunner.java) +- [CommonPropertyUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\CommonPropertyUtils.java) +- [Prioritized.java](file://datavines-spi\src\main\java\io\datavines\spi\Prioritized.java) + + +## 目录 +1. [引言](#引言) +2. [超时策略配置](#超时策略配置) +3. [任务执行超时时间设置](#任务执行超时时间设置) +4. [重试机制配置](#重试机制配置) +5. [任务优先级与资源抢占](#任务优先级与资源抢占) +6. [状态管理与监控配置](#状态管理与监控配置) +7. [业务场景配置示例](#业务场景配置示例) +8. [结论](#结论) + +## 引言 + +数据质量任务调度系统是确保数据可靠性与完整性的核心组件。本系统通过精细化的调度策略,实现了对数据质量检查任务的高效管理与执行。调度策略涵盖了超时处理、重试机制、优先级控制、资源管理等多个方面,能够根据任务的复杂度和数据量进行灵活配置。系统采用分布式架构,支持多种执行引擎(如Spark、Flink等),并提供了完善的监控和告警功能。通过合理的调度配置,可以确保关键业务数据得到及时、准确的检查,同时避免系统资源的过度消耗。 + +**本文档引用的文件** +- [TimeoutStrategy.java](file://datavines-common\src\main\java\io\datavines\common\enums\TimeoutStrategy.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +## 超时策略配置 + +超时策略定义了当数据质量检查任务执行超时时的处理方式。系统提供了两种主要的超时处理策略:重试(RETRY)和告警(WARN)。 + +- **重试策略 (RETRY)**:当任务执行超时时,系统会自动进行重试。该策略适用于那些可能因临时性问题(如网络波动、资源短暂不足)而失败的任务。通过重试机制,可以提高任务的最终成功率,确保数据检查的完整性。 +- **告警策略 (WARN)**:当任务执行超时时,系统不会自动重试,而是记录告警信息并通知相关人员。该策略适用于那些对实时性要求不高,或者重试成本较高的任务。通过告警,运维人员可以及时介入,分析问题原因并采取相应措施。 + +在系统中,`TimeoutStrategy` 枚举类定义了这两种策略。用户在创建数据质量检查任务时,可以根据业务需求选择合适的超时处理策略。例如,对于关键业务数据的检查,建议采用重试策略以确保检查成功;而对于非关键数据的检查,可以采用告警策略以节省系统资源。 + +```mermaid +graph TD +A[任务开始] --> B{是否超时?} +B --> |是| C[执行超时策略] +C --> D{策略类型} +D --> |RETRY| E[重试任务] +D --> |WARN| F[发送告警] +E --> G[任务成功] +F --> G +B --> |否| G +``` + +**图源** +- [TimeoutStrategy.java](file://datavines-common\src\main\java\io\datavines\common\enums\TimeoutStrategy.java) + +**本节源** +- [TimeoutStrategy.java](file://datavines-common\src\main\java\io\datavines\common\enums\TimeoutStrategy.java) + +## 任务执行超时时间设置 + +任务执行超时时间是调度策略中的关键参数,它定义了任务允许执行的最长时间。合理设置超时阈值对于平衡任务成功率和系统资源利用率至关重要。 + +### 超时时间配置 + +系统允许为每个数据质量检查任务单独配置超时时间。超时时间的设置应基于以下因素: +- **任务复杂度**:复杂的SQL查询或涉及大量数据聚合的任务需要更长的执行时间。 +- **数据量**:待检查的数据量越大,所需的处理时间越长。 +- **执行引擎性能**:不同的执行引擎(如Spark、Flink)和集群配置会影响任务的执行效率。 + +在 `JobExecutionRequest` 类中,`timeout` 字段用于存储任务的超时时间(单位:秒)。当任务的实际执行时间超过此阈值时,系统将触发超时处理流程。 + +### 超时阈值的合理配置 + +配置超时阈值时,建议遵循以下原则: +1. **基准测试**:在生产环境部署前,对典型任务进行多次执行,记录其执行时间的分布情况。 +2. **安全边际**:基于基准测试的平均或P95执行时间,增加20%-50%的安全边际作为超时阈值。 +3. **动态调整**:根据任务的历史执行情况,定期回顾和调整超时阈值。 + +例如,一个检查表行数的任务,如果历史平均执行时间为30秒,P95时间为45秒,则可以将超时阈值设置为60-70秒。 + +```mermaid +flowchart TD +Start([开始配置超时时间]) --> Benchmark["进行基准测试
记录执行时间"] +Benchmark --> Analyze["分析执行时间分布
计算平均值/P95"] +Analyze --> Calculate["计算超时阈值
= P95 * 1.5"] +Calculate --> Set["设置任务超时时间"] +Set --> Monitor["监控任务执行情况"] +Monitor --> Adjust{"是否需要调整?"} +Adjust --> |是| Calculate +Adjust --> |否| End([完成]) +``` + +**图源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +**本节源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +## 重试机制配置 + +重试机制是提高任务执行成功率的重要手段。系统提供了灵活的重试参数配置,包括重试次数、重试间隔和指数退避策略。 + +### 重试次数 + +重试次数定义了任务在失败后最多可以重试的次数。在 `JobExecutionRequest` 类中,`retryTimes` 字段用于配置此参数。用户应根据任务的性质和失败原因来设置重试次数: +- **临时性故障**:对于网络抖动、资源争用等临时性问题,可以设置较高的重试次数(如3-5次)。 +- **永久性故障**:对于数据源连接失败、SQL语法错误等永久性问题,重试通常无效,应设置较低的重试次数(如1-2次)或直接告警。 + +### 重试间隔与指数退避 + +重试间隔定义了两次重试之间的等待时间。为了避免对系统造成过大压力,系统支持指数退避策略。在 `JobScheduler` 类中,`RETRY_BACKOFF` 数组定义了重试的退避时间序列(单位:毫秒)。 + +指数退避策略的工作原理是:每次重试的等待时间按指数增长。例如,第一次重试等待1秒,第二次等待2秒,第三次等待4秒,以此类推。这种策略可以有效避免在系统故障期间产生大量的重试请求,给系统恢复留出时间。 + +```mermaid +sequenceDiagram +participant Scheduler as 调度器 +participant Task as 任务 +participant Retry as 重试机制 +Scheduler->>Task : 提交任务 +Task-->>Scheduler : 执行失败 +Retry->>Retry : 计算重试间隔
retryInterval * 2^n +Retry->>Scheduler : 等待指定时间 +Scheduler->>Task : 重新提交任务 +alt 重试成功 +Task-->>Scheduler : 执行成功 +else 重试失败 +Scheduler->>Retry : 检查重试次数 +Retry-->>Scheduler : 重试次数未达上限 +Retry->>Scheduler : 继续重试 +end +``` + +**图源** +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java) +- [JobRunner.java](file://datavines-runner\src\main\java\io\datavines\runner\JobRunner.java) + +**本节源** +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java) +- [JobRunner.java](file://datavines-runner\src\main\java\io\datavines\runner\JobRunner.java) + +## 任务优先级与资源抢占 + +任务优先级机制确保了关键任务能够优先获得系统资源。系统通过优先级设置和资源抢占机制来实现这一目标。 + +### 优先级设置 + +系统中的 `Prioritized` 接口定义了优先级机制。所有可优先化的组件都实现了此接口,并通过 `getPriority()` 方法返回其优先级值。优先级值越小,优先级越高。 + +在数据质量检查任务中,用户可以根据业务重要性为任务设置不同的优先级: +- **高优先级**:用于关键业务数据的检查,如核心交易数据、财务数据等。 +- **中优先级**:用于一般业务数据的检查。 +- **低优先级**:用于非关键数据或历史数据的检查。 + +### 资源抢占机制 + +资源抢占机制确保了高优先级任务能够及时执行。当系统资源紧张时,调度器会优先为高优先级任务分配资源。如果必要,系统甚至可以抢占低优先级任务的资源。 + +在 `JobScheduler` 类中,通过 `executionOutOfThreshold` 方法实现了资源使用阈值的控制。当某种执行引擎(如Spark)的并发任务数超过预设阈值时,新的任务将被延迟执行,从而避免系统过载。 + +```mermaid +graph TD +A[新任务提交] --> B{资源是否充足?} +B --> |是| C[立即执行] +B --> |否| D{任务优先级是否高?} +D --> |是| E[抢占资源
执行任务] +D --> |否| F[进入等待队列] +F --> G{资源释放?} +G --> |是| H[检查队列中任务优先级] +H --> I[执行最高优先级任务] +``` + +**图源** +- [Prioritized.java](file://datavines-spi\src\main\java\io\datavines\spi\Prioritized.java) +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java) + +**本节源** +- [Prioritized.java](file://datavines-spi\src\main\java\io\datavines\spi\Prioritized.java) +- [JobScheduler.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\runner\JobScheduler.java) + +## 状态管理与监控配置 + +有效的状态管理和监控是确保调度系统稳定运行的基础。系统提供了全面的任务状态跟踪、日志记录和异常处理机制。 + +### 任务状态跟踪 + +系统定义了完整的任务状态机,包括:等待执行、正在执行、执行成功、执行失败、已取消、已终止等状态。`ExecutionStatus` 枚举类管理了这些状态及其转换逻辑。 + +`JobExecuteManager` 类负责维护任务的执行状态。它使用 `unFinishedJobExecutionMap` 来跟踪所有未完成的任务,并通过 `HashedWheelTimer` 定时器来监控任务的执行时间,及时发现超时任务。 + +### 日志记录 + +系统采用分层的日志记录机制: +- **任务日志**:每个任务都有独立的日志文件,记录任务执行的详细过程。 +- **操作日志**:记录任务的调度、重试、超时等关键操作。 +- **错误日志**:专门收集和记录任务执行中的错误信息。 + +日志路径由 `JobExecutionLogDiscriminator` 类动态生成,确保日志文件的组织清晰有序。 + +### 异常处理 + +系统的异常处理流程如下: +1. 任务执行失败后,首先检查重试次数。 +2. 如果重试次数未耗尽,则按重试策略进行重试。 +3. 如果重试次数耗尽,则根据超时策略进行处理(重试或告警)。 +4. 最终,将任务状态更新为失败,并触发告警通知。 + +```mermaid +flowchart TD +A[任务开始] --> B[执行中] +B --> C{执行成功?} +C --> |是| D[更新为成功状态] +C --> |否| E{重试次数 > 0?} +E --> |是| F[等待重试间隔] +F --> G[重试任务] +G --> B +E --> |否| H{超时策略} +H --> |RETRY| I[再次重试] +H --> |WARN| J[发送告警] +J --> K[更新为失败状态] +D --> L[结束] +K --> L +``` + +**图源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +**本节源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +## 业务场景配置示例 + +以下是针对不同业务场景的调度策略配置示例: + +### 关键业务数据的严格检查 + +对于关键业务数据(如订单、支付等),应采用严格的检查策略: +- **超时策略**:RETRY,确保检查成功。 +- **超时时间**:设置较长的超时时间(如300秒),以应对大数据量的检查。 +- **重试机制**:重试次数设置为3次,采用指数退避策略。 +- **优先级**:设置为高优先级,确保及时执行。 +- **监控**:配置详细的日志记录和实时告警。 + +```json +{ + "taskName": "订单数据完整性检查", + "timeoutStrategy": "RETRY", + "timeout": 300, + "retryTimes": 3, + "retryInterval": 10, + "priority": "HIGH", + "notification": ["email", "dingtalk"] +} +``` + +### 非关键数据的宽松检查 + +对于非关键数据(如日志、埋点等),可以采用宽松的检查策略以节省资源: +- **超时策略**:WARN,避免无限重试消耗资源。 +- **超时时间**:设置较短的超时时间(如60秒)。 +- **重试机制**:重试次数设置为1次。 +- **优先级**:设置为低优先级。 +- **监控**:仅记录关键操作日志。 + +```json +{ + "taskName": "用户行为日志检查", + "timeoutStrategy": "WARN", + "timeout": 60, + "retryTimes": 1, + "retryInterval": 5, + "priority": "LOW", + "notification": ["email"] +} +``` + +**本节源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [CommonPropertyUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\CommonPropertyUtils.java) + +## 结论 + +本文档详细阐述了数据质量任务调度系统的各项策略配置。通过合理的超时策略、重试机制、优先级设置和监控配置,可以构建一个高效、可靠的调度系统。在实际应用中,应根据具体的业务需求和系统环境,灵活调整各项参数,以达到最佳的平衡。未来,系统可以进一步引入动态调度、智能预测等高级功能,以适应更复杂的业务场景。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\350\265\204\346\272\220\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\350\265\204\346\272\220\351\205\215\347\275\256.md" new file mode 100644 index 00000000..bc7dc431 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\211\247\350\241\214\351\205\215\347\275\256/\350\265\204\346\272\220\351\205\215\347\275\256.md" @@ -0,0 +1,265 @@ +# 资源配置 + + +**本文档引用的文件** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [FlinkParameters.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java) +- [SparkArgsUtils.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java) +- [FlinkArgsUtils.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java) +- [SparkConstants.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkConstants.java) +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) +- [FlinkConfiguration.tsx](file://datavines-ui/src/view/Main/Config/FlinkConfiguration.tsx) +- [FlinkConfig/index.tsx](file://datavines-ui/Editor/components/FlinkConfig/index.tsx) +- [ActuatorConfigure/index.tsx](file://datavines-ui/Editor/components/MetricModal/ActuatorConfigure/index.tsx) + + +## 目录 +1. [引言](#引言) +2. [核心资源配置参数](#核心资源配置参数) +3. [Spark执行平台资源配置](#spark执行平台资源配置) +4. [Flink执行平台资源配置](#flink执行平台资源配置) +5. [Local执行平台资源配置](#local执行平台资源配置) +6. [资源配置最佳实践](#资源配置最佳实践) +7. [性能影响分析与调优建议](#性能影响分析与调优建议) + +## 引言 +本文档全面介绍数据质量任务的资源配置参数,详细说明CPU、内存、并行度等核心资源的配置方法和优化策略。针对不同的执行平台(Spark、Flink和Local),解释相应的资源配置方式,并提供资源配置的最佳实践和性能调优建议。 + +## 核心资源配置参数 + +数据质量任务的资源配置主要涉及CPU、内存和并行度等核心参数。这些参数在不同执行平台上有不同的配置方式和优化策略。 + +**核心资源配置参数包括:** +- **CPU核心数**:控制任务执行的并行度 +- **内存分配**:为执行器和驱动器分配适当的内存 +- **并行度**:控制任务的并发执行程度 +- **堆外内存**:用于特定场景的内存配置 + +这些参数的合理配置对于任务的性能和稳定性至关重要。 + +**本节来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L26-L68) +- [FlinkParameters.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) + +## Spark执行平台资源配置 + +在Spark执行平台上,资源配置主要涉及Executor和Driver的配置。这些配置通过`SparkEngineParameter`类进行管理。 + +### Executor资源配置 +Executor是Spark中执行任务的工作进程,其资源配置包括: + +- **num-executors**:启动的Executor数量 +- **executor-cores**:每个Executor的CPU核心数 +- **executor-memory**:每个Executor的内存大小 + +```mermaid +flowchart TD +A[Spark执行平台] --> B[Executor资源配置] +B --> C[num-executors] +B --> D[executor-cores] +B --> E[executor-memory] +A --> F[Driver资源配置] +F --> G[driver-cores] +F --> H[driver-memory] +``` + +### Driver资源配置 +Driver是Spark应用程序的主控进程,其资源配置包括: + +- **driver-cores**:Driver使用的CPU核心数(仅在集群模式下使用) +- **driver-memory**:Driver的内存大小 + +### 配置实现 +Spark资源配置通过`SparkArgsUtils`类实现参数构建,将配置参数转换为Spark命令行参数。 + +```mermaid +classDiagram +class SparkEngineParameter { ++String programType ++String deployMode ++int driverCores ++String driverMemory ++int numExecutors ++int executorCores ++String executorMemory ++String others +} +class SparkArgsUtils { ++List buildArgs(SparkParameters param) +} +class SparkConstants { ++String DRIVER_CORES ++String DRIVER_MEMORY ++String NUM_EXECUTORS ++String EXECUTOR_CORES ++String EXECUTOR_MEMORY +} +SparkArgsUtils --> SparkEngineParameter : "使用" +SparkArgsUtils --> SparkConstants : "引用" +``` + +**本节来源** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L26-L68) +- [SparkArgsUtils.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java#L25-L131) +- [SparkConstants.java](file://datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkConstants.java#L19-L76) + +## Flink执行平台资源配置 + +在Flink执行平台上,资源配置主要涉及TaskManager和JobManager的配置。这些配置通过`FlinkParameters`类进行管理。 + +### TaskManager资源配置 +TaskManager是Flink中执行任务的工作进程,其资源配置包括: + +- **taskManagerCount**:TaskManager的数量 +- **taskManagerMemory**:每个TaskManager的内存大小 + +### JobManager资源配置 +JobManager是Flink的主控进程,其资源配置包括: + +- **jobManagerMemory**:JobManager的内存大小 + +### 并行度和Slot配置 +Flink的并行度和Slot配置是关键的性能参数: + +- **parallelism**:任务的并行度 +- **Slot**:TaskManager中的执行槽位 + +### 配置实现 +Flink资源配置通过`FlinkArgsUtils`类实现参数构建,将配置参数转换为Flink命令行参数。 + +```mermaid +flowchart TD +A[Flink执行平台] --> B[TaskManager资源配置] +B --> C[taskManagerCount] +B --> D[taskManagerMemory] +A --> E[JobManager资源配置] +E --> F[jobManagerMemory] +A --> G[并行度配置] +G --> H[parallelism] +``` + +```mermaid +classDiagram +class FlinkParameters { ++String mainJar ++String mainClass ++String deployMode ++String taskManagerCount ++String taskManagerMemory ++String jobManagerMemory ++String mainArgs ++String yarnQueue ++String jobName ++int parallelism ++String flinkOthers ++String jars ++String tags +} +class FlinkArgsUtils { ++List buildArgs(FlinkParameters param) +} +FlinkArgsUtils --> FlinkParameters : "使用" +``` + +**本节来源** +- [FlinkParameters.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) +- [FlinkArgsUtils.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L24-L104) +- [FlinkConfiguration.tsx](file://datavines-ui/src/view/Main/Config/FlinkConfiguration.tsx#L66-L84) +- [FlinkConfig/index.tsx](file://datavines-ui/Editor/components/FlinkConfig/index.tsx#L97-L121) + +## Local执行平台资源配置 + +在Local执行平台上,资源配置相对简单,主要用于开发和测试环境。 + +### 资源限制 +Local执行平台的资源限制包括: + +- **CPU核心数**:使用本地机器的CPU核心 +- **内存**:使用本地机器的内存 +- **并行度**:通常设置为1或根据机器配置调整 + +### 配置特点 +Local执行平台的配置特点: + +- 无需复杂的集群配置 +- 资源使用直接受限于本地机器 +- 适合小规模数据测试和开发 + +```mermaid +flowchart TD +A[Local执行平台] --> B[资源限制] +B --> C[CPU核心数] +B --> D[内存] +B --> E[并行度] +A --> F[适用场景] +F --> G[开发测试] +F --> H[小规模数据] +``` + +**本节来源** +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java#L290) +- [FlinkParameters.java](file://datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L28) + +## 资源配置最佳实践 + +### 资源估算方法 +根据数据量和复杂度进行资源估算: + +- **小规模数据**:少量Executor/TaskManager,较小内存 +- **中等规模数据**:适中数量的Executor/TaskManager,适中内存 +- **大规模数据**:大量Executor/TaskManager,较大内存 + +### 避免资源浪费或不足 +资源配置的平衡策略: + +- **避免资源浪费**:根据实际需求配置资源,避免过度配置 +- **避免资源不足**:确保有足够的资源处理数据,避免任务失败 + +### 配置示例 +```mermaid +flowchart TD +A[数据量] --> B{数据规模} +B --> |小| C[少量资源] +B --> |中| D[适中资源] +B --> |大| E[大量资源] +C --> F[1-2个Executor] +D --> G[3-5个Executor] +E --> H[6+个Executor] +``` + +**本节来源** +- [CatalogEntityInstanceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java#L974-L991) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java#L29-L79) + +## 性能影响分析与调优建议 + +### 性能影响因素 +资源配置对性能的主要影响: + +- **CPU核心数**:影响任务的并行处理能力 +- **内存大小**:影响数据处理的缓存能力和避免溢出 +- **并行度**:直接影响任务的执行速度 + +### 调优建议 +资源配置的调优策略: + +- **监控资源使用**:定期监控CPU和内存使用情况 +- **逐步调整**:从小配置开始,逐步增加直到性能稳定 +- **平衡配置**:确保CPU、内存和并行度的平衡 + +### 性能优化流程 +```mermaid +flowchart TD +A[初始配置] --> B[运行任务] +B --> C[监控性能] +C --> D{性能是否满意?} +D --> |是| E[完成] +D --> |否| F[调整资源配置] +F --> G[重新运行] +G --> C +``` + +**本节来源** +- [OSUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/OSUtils.java#L429-L434) +- [ActuatorConfigure/index.tsx](file://datavines-ui/Editor/components/MetricModal/ActuatorConfigure/index.tsx#L89-L202) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\225\260\346\215\256\350\264\250\351\207\217.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\225\260\346\215\256\350\264\250\351\207\217.md" new file mode 100644 index 00000000..b017af61 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\225\260\346\215\256\350\264\250\351\207\217.md" @@ -0,0 +1,246 @@ +# 数据质量 + + +**本文档引用的文件** +- [README.md](file://README.md) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [datavines-metric-plugins](file://datavines-metric/datavines-metric-plugins) +- [datavines-metric-expected-plugins](file://datavines-metric/datavines-metric-expected-plugins) +- [datavines-metric-result-formula-plugins](file://datavines-metric/datavines-metric-result-formula-plugins) + + +## 目录 +1. [引言](#引言) +2. [内置检查规则](#内置检查规则) +3. [质量检查执行流程](#质量检查执行流程) +4. [质量规则配置](#质量规则配置) +5. [检查结果计算与公式](#检查结果计算与公式) +6. [执行平台与调度策略](#执行平台与调度策略) +7. [结果存储、展示与告警](#结果存储展示与告警) +8. [使用示例与最佳实践](#使用示例与最佳实践) +9. [常见问题与优化](#常见问题与优化) + +## 引言 + +DataVines 是一个开源的数据质量服务与可观测性平台,旨在确保数据在集成和处理过程中的准确性。该平台提供全面的数据质量管理能力,支持多种数据质量检查规则,帮助用户构建可靠的数据质量保障体系。其核心功能包括数据目录、数据质量监控、数据概览等,支持插件化扩展,具备高可用性和易部署特性。 + +**Section sources** +- [README.md](file://README.md#L24-L57) +- [README.zh-CN.md](file://README.zh-CN.md#L26-L58) + +## 内置检查规则 + +DataVines 内置了27种数据质量检查规则,这些规则被组织为4种主要类型,以满足不同场景下的数据验证需求。 + +### 单表列检查 +此类规则针对单个数据表的特定列进行校验,是数据质量检查中最基础和最常用的类型。 + +- **非空检查** (`column_not_null`): 验证指定列中是否存在空值。 +- **唯一性检查** (`column_unique`): 确保指定列中的所有值都是唯一的,无重复。 +- **值范围检查** (`column_value_between`): 检查数值型列的值是否在预设的最小值和最大值之间。 +- **空值检查** (`column_null`): 统计并验证指定列中空值的数量。 +- **枚举值检查** (`column_in_enums`): 验证列的值是否在预定义的枚举列表中。 +- **正则匹配检查** (`column_match_regex`): 使用正则表达式验证列的值是否符合特定模式。 +- **正则不匹配检查** (`column_match_not_regex`): 验证列的值是否不匹配特定的正则表达式。 +- **长度检查** (`column_length`): 验证列值的字符长度。 +- **最大/最小值检查** (`column_max`, `column_min`): 检查列中的最大值或最小值。 +- **平均值检查** (`column_avg`): 计算并验证列的平均值。 +- **总和检查** (`column_sum`): 计算并验证列的总和。 +- **标准差/方差检查** (`column_std_dev`, `column_variance`): 计算列值的离散程度。 +- **去重计数检查** (`column_distinct`): 统计列中不同值的数量。 +- **重复值检查** (`column_duplicate`): 统计并列出列中的重复值。 +- **空白值检查** (`column_blank`): 识别并统计空字符串或仅包含空白字符的值。 +- **最大/最小长度检查** (`column_max_length`, `column_min_length`): 验证列值的最大或最小字符长度。 +- **平均长度检查** (`column_avg_length`): 计算列值的平均字符长度。 +- **直方图检查** (`column_histogram`): 对列值进行分桶统计,用于分析数据分布。 + +### 自定义SQL检查 +此类型允许用户编写自定义的SQL查询来定义检查逻辑,提供了极大的灵活性。 + +- **自定义聚合SQL检查** (`custom_aggregate_sql`): 用户可以编写任意的SELECT聚合查询(如`COUNT(*) WHERE ...`),其返回的单个数值将作为实际值进行后续的阈值判断。 + +### 跨表准确性检查 +此类规则用于验证两个表之间的数据一致性,确保数据在流转过程中没有丢失或损坏。 + +- **跨表准确性检查** (`multi_table_accuracy`): 通过比较源表和目标表的行数,计算数据的准确率,常用于ETL作业的完整性校验。 + +### 两表值比较检查 +此类规则用于比较两个表中特定字段的值,验证其数值上的差异。 + +- **两表值比对检查** (`multi_table_value_comparison`): 可以配置比较两个表中相同业务含义字段的聚合值(如SUM、AVG等),并设置允许的差异阈值。 + +**Section sources** +- [README.md](file://README.md#L46-L52) +- [README.zh-CN.md](file://README.zh-CN.md#L49-L54) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [datavines-metric-plugins](file://datavines-metric/datavines-metric-plugins) + +## 质量检查执行流程 + +数据质量检查任务的生命周期包含从创建到结果验证的完整流程,确保了检查的自动化和可追溯性。 + +1. **任务创建**: 用户通过Web界面或API创建一个质量检查任务,选择数据源、目标表、检查规则类型和具体的检查项。 +2. **参数构建**: 系统根据用户的选择,结合任务配置(如检查的列、阈值、预期值计算方式等),构建执行所需的参数。这些参数会传递给具体的`SqlMetric`实现。 +3. **执行调度**: 任务被提交到调度系统(如Quartz),根据配置的调度策略(如一次性、每日、每周等)进行调度。调度器负责在预定时间触发任务执行。 +4. **引擎执行**: 根据任务配置的执行引擎(Spark、Flink、Local等),系统调用相应的`EngineExecutor`。执行器会生成并提交具体的执行命令(如Spark-submit)。 +5. **SQL生成与执行**: 在执行器内部,具体的`SqlMetric`插件会根据`getActualValue`方法生成用于计算实际值的SQL语句,并通过`JdbcExecutorClient`或对应的引擎客户端执行该SQL。 +6. **结果获取与计算**: 执行引擎返回SQL查询结果(实际值)。系统根据配置的`ExpectedValue`插件计算预期值(可能通过查询历史数据或使用固定值),然后使用`ResultFormula`插件计算最终结果(如百分比、差异值)。 +7. **结果验证与存储**: 将计算出的结果与用户设定的阈值进行比较,判断检查是否成功。最终的检查结果(包括实际值、预期值、得分、状态等)被持久化存储到系统数据库中。 +8. **告警与展示**: 如果检查失败或达到告警条件,系统会通过配置的告警通道(如邮件)发送通知。用户可以在Web界面上查看历史检查报告、执行日志和错误数据。 + +```mermaid +flowchart TD +A[创建检查任务] --> B[构建任务参数] +B --> C[调度器触发] +C --> D[选择执行引擎] +D --> E[生成检查SQL] +E --> F[执行SQL获取实际值] +F --> G[计算预期值] +G --> H[应用结果公式] +H --> I[与阈值比较] +I --> J{检查通过?} +J --> |是| K[存储成功结果] +J --> |否| L[存储失败结果] +K --> M[展示结果] +L --> M +L --> N[发送告警通知] +``` + +**Diagram sources** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L59) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java#L48) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java#L34) + +**Section sources** +- [README.md](file://README.md#L53-L54) +- [README.zh-CN.md](file://README.zh-CN.md#L55-L56) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [datavines-engine](file://datavines-engine) + +## 质量规则配置 + +质量规则的配置是数据质量检查的核心,它定义了检查的具体行为和判断标准。 + +### 阈值设置 +每个检查规则都允许用户设置一个阈值,用于与计算出的结果进行比较。阈值可以是: +- **固定值**: 例如,要求非空检查的通过率必须大于95%。 +- **动态值**: 通过与预期值的比较来动态判断,例如,两表比对的差异值必须小于100。 + +### 预期值计算 +预期值是衡量实际值是否合格的基准。DataVines支持多种预期值计算方式,通过`ExpectedValue` SPI插件实现: + +- **固定值** (`fix_value`): 预期值为用户直接输入的常量。 +- **无预期值** (`none`): 仅使用实际值与固定阈值比较,不涉及预期值计算。 +- **历史平均值**: + - **日平均值** (`daily_avg`): 计算过去每天检查结果的平均值。 + - **周平均值** (`weekly_avg`): 计算过去每周检查结果的平均值。 + - **月平均值** (`monthly_avg`): 计算过去每月检查结果的平均值。 + - **最近7天/30天平均值** (`last7day_avg`, `last30day_avg`): 计算最近7天或30天内检查结果的平均值。 +- **表行数** (`table_rows`): 将当前表的总行数作为预期值,常用于与其他表进行比对。 +- **目标表行数** (`target_table_rows`): 将另一个目标表的行数作为预期值。 + +### 结果公式 +结果公式定义了如何将实际值和预期值组合成一个有意义的度量结果。通过`ResultFormula` SPI插件实现: + +- **百分比** (`percentage`): `实际值 / 预期值 * 100%`,常用于计算准确率、完整率。 +- **差异值** (`diff`): `实际值 - 预期值`,用于计算绝对差异。 +- **差异百分比** (`diff_percentage`): `(实际值 - 预期值) / 预期值 * 100%`,用于计算相对差异。 +- **计数** (`count`): 直接使用实际值作为结果,通常用于空值、重复值等计数场景。 + +**Section sources** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [datavines-metric-expected-plugins](file://datavines-metric/datavines-metric-expected-plugins) +- [datavines-metric-result-formula-plugins](file://datavines-metric/datavines-metric-result-formula-plugins) + +## 检查结果计算与公式 + +检查结果的计算是连接实际数据与质量判断的桥梁。其核心是`ResultFormula`接口的`getResult`方法。 + +1. **获取实际值**: 通过执行`SqlMetric`的`getActualValue`方法返回的SQL,从数据源中查询得到一个`BigDecimal`类型的数值。 +2. **获取预期值**: 根据配置的`ExpectedValue`类型,系统计算或获取一个`BigDecimal`类型的预期值。 +3. **应用公式**: 将实际值和预期值作为参数,传入`ResultFormula`的`getResult`方法进行计算。 + - 例如,使用`Percentage`公式时,计算过程为 `actualValue.divide(expectedValue, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("100"))`。 +4. **结果判断**: 将计算出的结果与用户在任务中设置的阈值进行比较。如果结果满足阈值条件(如 `结果 >= 阈值`),则检查通过;否则,检查失败。 + +此机制使得DataVines能够灵活地适应各种质量度量场景,从简单的计数到复杂的比率分析。 + +**Section sources** +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java#L34) + +## 执行平台与调度策略 + +DataVines支持多种执行平台和灵活的调度策略,以适应不同的生产环境和性能需求。 + +### 执行平台 +- **Spark**: 基于Spark引擎执行,适用于大规模数据集的检查,性能优越。目前主要支持Spark 2.4版本。 +- **Local (JDBC)**: 基于JDBC的本地执行引擎,无需依赖外部计算框架,部署简单,适用于小数据量或功能验证场景。 +- **Flink**: 支持基于Flink引擎执行,适用于流批一体的数据质量监控场景。 +- **Livy**: 通过Livy服务提交Spark作业,提供更灵活的集群交互方式。 + +### 调度策略 +- **定时调度**: 支持Cron表达式,可以配置任务按分钟、小时、天、周、月等周期自动执行。 +- **手动触发**: 用户可以通过Web界面或API手动触发单次检查任务。 +- **依赖调度**: (未来可能支持)支持任务间的依赖关系,例如,只有当上游数据同步任务完成后,才触发数据质量检查。 + +**Section sources** +- [README.md](file://README.md#L73) +- [README.zh-CN.md](file://README.zh-CN.md#L75) +- [datavines-engine-plugins](file://datavines-engine/datavines-engine-plugins) + +## 结果存储、展示与告警 + +检查结果的全生命周期管理是保障数据质量闭环的关键。 + +### 结果存储 +检查的最终结果(包括任务ID、检查项、实际值、预期值、计算结果、状态、执行时间等)会被持久化存储在DataVines的系统数据库(如MySQL)中,便于历史追溯和分析。 + +### 结果展示 +- **Web界面**: 用户可以通过DataVines的UI界面查看详细的检查报告,包括历史趋势图、执行日志、以及在检查中发现的错误数据详情。 +- **API接口**: 提供RESTful API,方便与其他系统集成,获取检查结果。 + +### 告警机制 +- **SLA告警**: 用户可以为检查任务配置SLA(服务等级协议),当检查失败或结果低于设定的阈值时,系统会自动触发告警。 +- **告警通道**: 目前支持邮件告警,未来可能扩展支持钉钉、企业微信等更多通道。 +- **通知内容**: 告警通知会包含任务名称、失败原因、实际值、预期值等关键信息,帮助用户快速定位问题。 + +**Section sources** +- [README.md](file://README.md#L54-L55) +- [README.zh-CN.md](file://README.zh-CN.md#L56) +- [datavines-notification](file://datavines-notification) + +## 使用示例与最佳实践 + +### 使用示例 +1. **核心表非空检查**: 为用户表(`user_info`)的`user_id`列配置`column_not_null`规则,预期值为表总行数,使用`percentage`公式,阈值设为100%,确保主键无空值。 +2. **订单金额范围检查**: 为订单表(`orders`)的`amount`列配置`column_value_between`规则,设置最小值为0,最大值为100000,防止异常数据。 +3. **ETL作业完整性校验**: 为源表`ods_orders`和目标表`dwd_orders`配置`multi_table_accuracy`规则,确保每日ETL后两表行数一致。 + +### 最佳实践 +- **分层检查**: 对核心业务表实施更严格的检查(如100%非空),对非核心表可适当放宽阈值。 +- **渐进式监控**: 初期可先监控关键指标,待系统稳定后,再逐步增加检查项。 +- **合理设置阈值**: 阈值应基于业务实际情况设定,避免过于严格导致频繁告警,或过于宽松失去监控意义。 +- **利用历史数据**: 对于波动性较大的指标,使用“历史平均值”作为预期值比固定值更科学。 + +**Section sources** +- [README.md](file://README.md#L53-L56) +- [README.zh-CN.md](file://README.zh-CN.md#L55-L57) + +## 常见问题与优化 + +### 常见问题 +- **检查性能慢**: 对于大表检查,应优先选择Spark引擎,并优化检查SQL(如添加索引、避免全表扫描)。 +- **复杂规则配置**: 对于复杂的业务逻辑,建议使用“自定义SQL检查”来实现。 +- **预期值不准确**: 确保用于计算历史平均值的数据源是可靠的,避免因历史数据错误导致预期值偏差。 + +### 性能优化 +- **选择合适的引擎**: 大数据量选择Spark,小数据量选择Local引擎以减少开销。 +- **优化SQL**: 在`SqlMetric`的实现中,确保生成的SQL是高效的,利用数据库索引。 +- **合理调度**: 避免在业务高峰期执行大规模检查任务。 + +**Section sources** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [datavines-engine](file://datavines-engine) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\344\270\232\345\212\241\350\247\204\345\210\231\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\344\270\232\345\212\241\350\247\204\345\210\231\346\243\200\346\237\245.md" new file mode 100644 index 00000000..9dbc705c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\344\270\232\345\212\241\350\247\204\345\210\231\346\243\200\346\237\245.md" @@ -0,0 +1,188 @@ +# 业务规则检查 + + +**本文档引用的文件** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) +- [Validate.java](file://datavines-common\src\main\java\io\datavines\common\param\form\Validate.java) +- [TaskParameter.java](file://datavines-client\datavines-http-client\datavines-http-client-core\src\main\java\io\datavines\http\client\request\TaskParameter.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 引言 +DataVines是一个数据质量监控平台,提供多种业务规则检查功能。本文档重点介绍单表列业务规则中的值范围检查(ColumnValueBetween)功能,该功能用于验证数值型字段是否在业务定义的合理区间内。通过分析代码实现,我们将详细说明该规则的配置参数、使用场景、性能优化建议以及与执行引擎的集成方式。 + +## 核心组件 +值范围检查规则(ColumnValueBetween)是DataVines中用于验证数据字段值是否在指定范围内的核心组件。该组件允许用户定义最小值和最大值,并可选择是否包含边界值。此规则适用于数值型、字符串型和日期时间型数据,广泛应用于年龄验证、价格校验等业务场景。 + +**Section sources** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L31-L82) + +## 架构概述 +DataVines的业务规则检查架构采用插件化设计,将规则定义、SQL生成和执行分离。值范围检查规则作为单表指标插件实现,通过继承BaseSingleTable基类获得基本功能,并利用MetricScript接口生成针对不同数据库的SQL语句。整个架构支持多种数据源,包括MySQL、Oracle、PostgreSQL等,通过SPI机制动态加载相应的连接器和脚本生成器。 + +```mermaid +graph TD +A[业务规则配置] --> B[ColumnValueBetween规则] +B --> C[BaseSingleTable基类] +C --> D[MetricScript接口] +D --> E[JDBC连接器] +D --> F[MySQL连接器] +D --> G[Oracle连接器] +D --> H[PostgreSQL连接器] +E --> I[执行引擎] +F --> I +G --> I +H --> I +I --> J[数据库] +``` + +**Diagram sources** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L31-L82) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L33-L100) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L59-L101) + +## 详细组件分析 + +### ColumnValueBetween规则分析 +ColumnValueBetween规则实现了对数据字段值范围的验证。该规则通过配置最小值和最大值来定义合法的数据区间,并可选择是否包含边界值。规则支持数值型、字符串型和日期时间型数据,适用于各种业务场景。 + +#### 配置参数 +该规则提供以下配置参数: + +| 参数 | 描述 | 必需 | +|------|------|------| +| min | 最小值 | 否 | +| max | 最大值 | 否 | +| table | 表名 | 是 | +| filter | 过滤条件 | 否 | + +```mermaid +classDiagram +class ColumnValueBetween { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map config) ++List suitableType() +} +class BaseSingleTable { ++StringBuilder invalidateItemsSql ++List filters ++HashMap configMap ++Set requiredOptions ++void prepare(Map config) ++ExecuteSql getInvalidateItems(Map inputParameter) ++ExecuteSql getActualValue(Map inputParameter) ++CheckResult validateConfig(Map config) ++ConnectorFactory getConnectorFactory(Map inputParameter) +} +ColumnValueBetween --> BaseSingleTable : "继承" +``` + +**Diagram sources** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L31-L82) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L33-L100) + +### SQL生成机制 +值范围检查规则通过MetricScript接口生成SQL语句。当配置了最小值时,系统调用columnGteMin()方法生成大于等于最小值的条件;当配置了最大值时,系统调用columnLteMax()方法生成小于等于最大值的条件。这些条件通过AND操作符连接,形成完整的WHERE子句。 + +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant ColumnValueBetween as ColumnValueBetween规则 +participant BaseSingleTable as BaseSingleTable基类 +participant MetricScript as MetricScript接口 +participant 数据库 as 数据库 +用户->>ColumnValueBetween : 配置min=0, max=150 +ColumnValueBetween->>ColumnValueBetween : prepare(config) +ColumnValueBetween->>BaseSingleTable : getConnectorFactory(config) +BaseSingleTable->>MetricScript : columnGteMin() +MetricScript-->>ColumnValueBetween : "${column} >= ${min}" +ColumnValueBetween->>MetricScript : columnLteMax() +MetricScript-->>ColumnValueBetween : "${column} <= ${max}" +ColumnValueBetween->>数据库 : 执行SQL查询 +数据库-->>用户 : 返回检查结果 +``` + +**Diagram sources** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L65-L76) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L59-L101) + +## 依赖分析 +值范围检查规则依赖于多个核心组件,包括BaseSingleTable基类、MetricScript接口和具体的数据库连接器。这些组件通过SPI机制动态加载,确保了系统的可扩展性和灵活性。 + +```mermaid +graph TD +A[ColumnValueBetween] --> B[BaseSingleTable] +A --> C[MetricScript] +C --> D[JdbcMetricScript] +C --> E[MysqlMetricScript] +C --> F[OracleMetricScript] +C --> G[PostgreSqlMetricScript] +B --> H[ConnectorFactory] +H --> I[JdbcConnector] +H --> J[MysqlConnector] +H --> K[OracleConnector] +H --> L[PostgreSqlConnector] +``` + +**Diagram sources** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L31-L82) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L33-L100) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L59-L101) + +**Section sources** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L31-L82) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L33-L100) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L59-L101) + +## 性能考虑 +值范围检查规则的性能主要受以下因素影响: +1. **索引使用**:在被检查的列上创建索引可以显著提高查询性能。 +2. **数据量**:大数据量的表需要更长的检查时间,建议在非高峰时段执行检查。 +3. **过滤条件**:复杂的过滤条件会增加查询复杂度,影响性能。 +4. **并行执行**:多个规则可以并行执行,提高整体检查效率。 + +为了优化性能,建议: +- 在经常检查的列上创建适当的索引 +- 避免在高峰时段执行大规模数据检查 +- 使用分区表来减少每次检查的数据量 +- 合理配置检查频率,避免过于频繁的检查 + +**Section sources** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L31-L82) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L33-L100) + +## 故障排除指南 +在使用值范围检查规则时,可能会遇到以下常见问题: + +1. **配置错误**:确保最小值小于最大值,且数据类型匹配。 +2. **SQL语法错误**:检查生成的SQL语句是否符合目标数据库的语法要求。 +3. **性能问题**:如果检查执行时间过长,考虑优化查询或增加索引。 +4. **数据类型不匹配**:确保检查的列数据类型与配置的类型一致。 + +对于问题排查,可以: +- 检查日志文件中的错误信息 +- 验证生成的SQL语句是否正确 +- 使用数据库的执行计划分析工具优化查询 +- 确认连接配置和权限设置 + +**Section sources** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L31-L82) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L33-L100) +- [Validate.java](file://datavines-common\src\main\java\io\datavines\common\param\form\Validate.java#L41-L136) + +## 结论 +值范围检查规则(ColumnValueBetween)是DataVines中一个重要的业务规则检查功能,能够有效验证数据字段值是否在合理的业务范围内。通过灵活的配置参数和可扩展的架构设计,该规则适用于各种业务场景,如年龄验证、价格校验等。结合适当的性能优化措施,可以确保数据质量检查的高效性和准确性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\345\215\225\350\241\250\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\345\215\225\350\241\250\346\243\200\346\237\245.md" new file mode 100644 index 00000000..4b0b2c95 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\345\215\225\350\241\250\346\243\200\346\237\245.md" @@ -0,0 +1,572 @@ +# 单表检查 + + +**本文档引用的文件** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [ColumnInEnums.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-in-enums\src\main\java\io\datavines\metric\plugin\ColumnInEnums.java) +- [ColumnMatchRegex.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-match-regex\src\main\java\io\datavines\metric\plugin\ColumnMatchRegex.java) +- [ColumnLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-length\src\main\java\io\datavines\metric\plugin\ColumnLength.java) +- [ColumnAvgLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg-length\src\main\java\io\datavines\metric\plugin\ColumnAvgLength.java) +- [ColumnStdDev.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-std-dev\src\main\java\io\datavines\metric\plugin\ColumnStdDev.java) +- [ColumnVariance.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-variance\src\main\java\io\datavines\metric\plugin\ColumnVariance.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) +- [BaseSingleTableColumn.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumn.java) + + +## 目录 +1. [引言](#引言) +2. [核心架构与实现原理](#核心架构与实现原理) +3. [单表列级质量检查规则详解](#单表列级质量检查规则详解) + 1. [非空检查(ColumnNotNull)](#非空检查columnnotnull) + 2. [唯一性检查(ColumnUnique)](#唯一性检查columnunique) + 3. [值范围检查(ColumnValueBetween)](#值范围检查columnvaluebetween) + 4. [枚举值检查(ColumnInEnums)](#枚举值检查columninenums) + 5. [正则匹配检查(ColumnMatchRegex)](#正则匹配检查columnmatchregex) + 6. [长度检查(ColumnLength)](#长度检查columnlength) + 7. [平均长度检查(ColumnAvgLength)](#平均长度检查columnavglength) + 8. [标准差检查(ColumnStdDev)](#标准差检查columnstddev) + 9. [方差检查(ColumnVariance)](#方差检查columnvariance) +4. [执行引擎集成机制](#执行引擎集成机制) +5. [实际业务场景应用案例](#实际业务场景应用案例) +6. [性能优化建议](#性能优化建议) +7. [结论](#结论) + +## 引言 + +DataVines是一个数据质量监控平台,提供丰富的单表列级质量检查规则。这些规则通过统一的`SqlMetric`接口实现,能够对数据表中的特定列进行各种质量验证。本文档详细描述了DataVines支持的单表列级质量检查规则的实现原理、配置参数、使用场景和性能优化建议。 + +## 核心架构与实现原理 + +DataVines的质量检查规则基于`SqlMetric`接口实现,该接口定义了所有质量指标必须实现的核心方法。所有单表列级检查规则都继承自`BaseSingleTableColumn`或`BaseSingleTableColumnNotUseView`基类,这些基类提供了通用的功能和配置管理。 + +```mermaid +classDiagram +class SqlMetric { +<> ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class BaseSingleTable { ++Map~String,ConfigItem~ configMap ++String[] requiredOptions ++StringBuilder invalidateItemsSql ++ConnectorFactory getConnectorFactory(Map~String,String~) ++void prepare(Map~String,String~) +} +class BaseSingleTableColumn { ++BaseSingleTableColumn() ++Map~String,ConfigItem~ getConfigMap() ++MetricLevel getLevel() ++boolean isInvalidateItemsCanOutput() +} +class BaseSingleTableColumnNotUseView { ++BaseSingleTableColumnNotUseView() ++Map~String,ConfigItem~ getConfigMap() ++MetricLevel getLevel() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getDirectActualValue(Map~String,String~) +} +class ColumnNotNull { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnUnique { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnValueBetween { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnInEnums { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnMatchRegex { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnLength { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnAvgLength { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnStdDev { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnVariance { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++DataVinesDataType[] suitableType() +} +SqlMetric <|-- BaseSingleTable +BaseSingleTable <|-- BaseSingleTableColumn +BaseSingleTable <|-- BaseSingleTableColumnNotUseView +BaseSingleTableColumn <|-- ColumnAvgLength +BaseSingleTableColumn <|-- ColumnStdDev +BaseSingleTableColumn <|-- ColumnVariance +BaseSingleTableColumnNotUseView <|-- ColumnNotNull +BaseSingleTableColumnNotUseView <|-- ColumnUnique +BaseSingleTableColumnNotUseView <|-- ColumnValueBetween +BaseSingleTableColumnNotUseView <|-- ColumnInEnums +BaseSingleTableColumnNotUseView <|-- ColumnMatchRegex +BaseSingleTableColumnNotUseView <|-- ColumnLength +``` + +**图表来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTableColumn.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumn.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) + +**章节来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTableColumn.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumn.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) + +## 单表列级质量检查规则详解 + +### 非空检查(ColumnNotNull) + +非空检查用于验证指定列中是否存在空值,确保数据的完整性。 + +**实现原理**: +- 继承自`BaseSingleTableColumnNotUseView` +- 通过`columnNotNull()`方法生成SQL过滤条件 +- 在`prepare`方法中添加非空过滤器 + +**配置参数**: +- `column`: 要检查的列名(必填) +- `filter`: 附加的WHERE条件(可选) + +**适用数据类型**: +- 数值类型(NUMERIC_TYPE) +- 字符串类型(STRING_TYPE) +- 日期时间类型(DATE_TIME_TYPE) + +**使用场景**: +- 用户表中的手机号、邮箱等关键字段不能为空 +- 订单表中的订单号、用户ID等核心字段必须有值 + +**性能优化建议**: +- 为检查的列创建索引以提高查询性能 +- 避免在大表上频繁执行非空检查 +- 可以结合分区条件进行检查,减少扫描数据量 + +**章节来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) + +### 唯一性检查(ColumnUnique) + +唯一性检查用于验证指定列中的值是否唯一,防止重复数据的出现。 + +**实现原理**: +- 继承自`BaseSingleTableColumnNotUseView` +- 在`prepare`方法中构建包含`GROUP BY`和`HAVING COUNT(*) > 1`的SQL语句 +- 使用`groupByHavingCountForUnique()`方法生成分组和计数条件 + +**配置参数**: +- `column`: 要检查的列名(必填) +- `filter`: 附加的WHERE条件(可选) + +**适用数据类型**: +- 数值类型(NUMERIC_TYPE) +- 字符串类型(STRING_TYPE) +- 日期时间类型(DATE_TIME_TYPE) + +**使用场景**: +- 用户表中的用户ID、手机号必须唯一 +- 订单表中的订单号必须唯一 +- 产品表中的产品编码必须唯一 + +**性能优化建议**: +- 为检查的列创建唯一索引,既保证数据质量又提高查询性能 +- 对于大表,考虑使用采样方式检查唯一性 +- 避免在没有索引的列上执行唯一性检查 + +**章节来源** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) + +### 值范围检查(ColumnValueBetween) + +值范围检查用于验证指定列的值是否在预设的最小值和最大值之间。 + +**实现原理**: +- 继承自`BaseSingleTableColumnNotUseView` +- 在`prepare`方法中根据配置的`min`和`max`值添加相应的过滤条件 +- 使用`columnGteMin()`和`columnLteMax()`方法生成大于等于最小值和小于等于最大值的条件 + +**配置参数**: +- `column`: 要检查的列名(必填) +- `min`: 最小值(可选) +- `max`: 最大值(可选) +- `filter`: 附加的WHERE条件(可选) + +**适用数据类型**: +- 数值类型(NUMERIC_TYPE) +- 字符串类型(STRING_TYPE) +- 日期时间类型(DATE_TIME_TYPE) + +**使用场景**: +- 产品表中的价格应在合理范围内 +- 用户表中的年龄应在0-150之间 +- 订单表中的订单金额应为正数 + +**性能优化建议**: +- 为检查的列创建索引,特别是范围查询频繁的列 +- 避免在大表上频繁执行范围检查 +- 可以结合业务逻辑设置合理的范围值 + +**章节来源** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) + +### 枚举值检查(ColumnInEnums) + +枚举值检查用于验证指定列的值是否在预设的枚举值列表中。 + +**实现原理**: +- 继承自`BaseSingleTableColumnNotUseView` +- 在`prepare`方法中添加`IN`条件过滤器 +- 使用`columnInEnums()`方法生成IN子句 + +**配置参数**: +- `column`: 要检查的列名(必填) +- `enum_list`: 枚举值列表,用逗号分隔(必填) +- `filter`: 附加的WHERE条件(可选) + +**适用数据类型**: +- 数值类型(NUMERIC_TYPE) +- 字符串类型(STRING_TYPE) +- 日期时间类型(DATE_TIME_TYPE) + +**使用场景**: +- 用户表中的性别字段只能是"男"或"女" +- 订单表中的订单状态只能是预设的几种状态 +- 产品表中的产品类别必须在定义的类别中 + +**性能优化建议**: +- 对于枚举值较多的情况,考虑使用字典表关联查询 +- 为检查的列创建索引以提高IN查询性能 +- 枚举值列表不宜过大,否则会影响查询性能 + +**章节来源** +- [ColumnInEnums.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-in-enums\src\main\java\io\datavines\metric\plugin\ColumnInEnums.java) + +### 正则匹配检查(ColumnMatchRegex) + +正则匹配检查用于验证指定列的值是否符合预设的正则表达式模式。 + +**实现原理**: +- 继承自`BaseSingleTableColumnNotUseView` +- 在`prepare`方法中添加正则匹配过滤器 +- 使用`columnMatchRegex()`方法生成正则匹配条件 + +**配置参数**: +- `column`: 要检查的列名(必填) +- `regexp`: 正则表达式(必填) +- `filter`: 附加的WHERE条件(可选) + +**适用数据类型**: +- 字符串类型(STRING_TYPE) +- 日期时间类型(DATE_TIME_TYPE) + +**使用场景**: +- 用户表中的手机号必须符合手机号格式 +- 邮箱字段必须符合邮箱格式 +- 身份证号码必须符合身份证号码格式 + +**性能优化建议**: +- 正则表达式应尽量简洁高效,避免复杂的正则模式 +- 避免在大表上频繁执行正则匹配检查 +- 可以先通过简单的长度或前缀检查过滤大部分数据,再进行正则匹配 + +**章节来源** +- [ColumnMatchRegex.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-match-regex\src\main\java\io\datavines\metric\plugin\ColumnMatchRegex.java) + +### 长度检查(ColumnLength) + +长度检查用于验证指定列的值长度是否符合预设条件。 + +**实现原理**: +- 继承自`BaseSingleTableColumnNotUseView` +- 在`prepare`方法中根据配置的长度和比较符添加过滤条件 +- 使用`columnLengthCompare()`方法生成长度比较条件 + +**配置参数**: +- `column`: 要检查的列名(必填) +- `length`: 目标长度值(必填) +- `comparator`: 比较符,如=、!=、>、>=、<、<=(必填) +- `filter`: 附加的WHERE条件(可选) + +**适用数据类型**: +- 字符串类型(STRING_TYPE) +- 日期时间类型(DATE_TIME_TYPE) + +**使用场景**: +- 用户名长度应在4-20个字符之间 +- 密码长度应不少于8个字符 +- 手机号长度必须为11位 + +**性能优化建议**: +- 为检查的列创建索引,特别是长度检查频繁的列 +- 避免在大文本字段上执行长度检查 +- 可以结合业务逻辑设置合理的长度范围 + +**章节来源** +- [ColumnLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-length\src\main\java\io\datavines\metric\plugin\ColumnLength.java) + +### 平均长度检查(ColumnAvgLength) + +平均长度检查用于计算指定列值的平均长度。 + +**实现原理**: +- 继承自`BaseSingleTableColumn` +- 重写`getActualValue`方法,使用`avgLengthActualValue()`方法生成计算平均长度的SQL +- 不支持输出无效项,`getInvalidateItems`方法返回null + +**配置参数**: +- `column`: 要检查的列名(必填) +- `filter`: 附加的WHERE条件(可选) + +**适用数据类型**: +- 数值类型(NUMERIC_TYPE) +- 字符串类型(STRING_TYPE) +- 日期时间类型(DATE_TIME_TYPE) + +**使用场景**: +- 分析用户昵称的平均长度 +- 监控产品描述字段的平均长度变化 +- 评估评论内容的平均长度趋势 + +**性能优化建议**: +- 为检查的列创建索引以提高聚合查询性能 +- 避免在大表上频繁执行平均长度计算 +- 可以结合采样方式估算平均长度 + +**章节来源** +- [ColumnAvgLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg-length\src\main\java\io\datavines\metric\plugin\ColumnAvgLength.java) + +### 标准差检查(ColumnStdDev) + +标准差检查用于计算指定列数值的标准差,衡量数据的离散程度。 + +**实现原理**: +- 继承自`BaseSingleTableColumn` +- 重写`getActualValue`方法,使用`stdDevActualValue()`方法生成计算标准差的SQL +- 不支持输出无效项,`getInvalidateItems`方法返回null +- 仅适用于数值类型数据 + +**配置参数**: +- `column`: 要检查的列名(必填) +- `filter`: 附加的WHERE条件(可选) + +**适用数据类型**: +- 数值类型(NUMERIC_TYPE) + +**使用场景**: +- 分析订单金额的波动情况 +- 监控用户消费金额的标准差变化 +- 评估产品价格的离散程度 + +**性能优化建议**: +- 为检查的列创建索引以提高聚合查询性能 +- 避免在大表上频繁执行标准差计算 +- 可以结合时间窗口分析标准差的变化趋势 + +**章节来源** +- [ColumnStdDev.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-std-dev\src\main\java\io\datavines\metric\plugin\ColumnStdDev.java) + +### 方差检查(ColumnVariance) + +方差检查用于计算指定列数值的方差,衡量数据的离散程度。 + +**实现原理**: +- 继承自`BaseSingleTableColumn` +- 重写`getActualValue`方法,使用`varianceActualValue()`方法生成计算方差的SQL +- 不支持输出无效项,`getInvalidateItems`方法返回null +- 仅适用于数值类型数据 + +**配置参数**: +- `column`: 要检查的列名(必填) +- `filter`: 附加的WHERE条件(可选) + +**适用数据类型**: +- 数值类型(NUMERIC_TYPE) + +**使用场景**: +- 分析股票价格的方差 +- 监控系统响应时间的方差变化 +- 评估产品质量指标的稳定性 + +**性能优化建议**: +- 为检查的列创建索引以提高聚合查询性能 +- 避免在大表上频繁执行方差计算 +- 可以结合标准差一起分析数据的离散程度 + +**章节来源** +- [ColumnVariance.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-variance\src\main\java\io\datavines\metric\plugin\ColumnVariance.java) + +## 执行引擎集成机制 + +DataVines的质量检查规则通过`SqlMetric`接口与执行引擎集成。当配置一个质量检查任务时,系统会根据配置的指标类型加载相应的`SqlMetric`实现类,并调用其方法生成执行SQL。 + +```mermaid +sequenceDiagram +participant UI as 用户界面 +participant Server as DataVines服务器 +participant Engine as 执行引擎 +participant Database as 目标数据库 +UI->>Server : 提交质量检查任务配置 +Server->>Server : 解析配置,确定指标类型 +Server->>Server : 通过SPI加载对应的SqlMetric实现 +Server->>Server : 调用prepare()方法准备配置 +Server->>Server : 调用getActualValue()生成SQL +Server->>Engine : 提交执行任务 +Engine->>Database : 执行生成的SQL +Database-->>Engine : 返回查询结果 +Engine-->>Server : 返回执行结果 +Server-->>UI : 显示质量检查结果 +``` + +**图表来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- 各具体指标实现类 + +**章节来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) + +## 实际业务场景应用案例 + +### 用户表手机号非空验证 + +在用户管理系统中,手机号是关键的联系方式,必须确保其非空。 + +```json +{ + "metric_type": "column_not_null", + "config": { + "column": "phone_number", + "filter": "status = 'ACTIVE'" + } +} +``` + +此配置将检查活跃用户表中手机号字段的非空情况,确保所有活跃用户的手机号都不为空。 + +### 订单表订单号唯一性校验 + +订单号是订单的唯一标识,必须保证其唯一性。 + +```json +{ + "metric_type": "column_unique", + "config": { + "column": "order_id", + "filter": "create_time >= '2023-01-01'" + } +} +``` + +此配置将检查2023年以来创建的订单中订单号的唯一性,防止订单号重复。 + +### 产品表价格范围校验 + +产品价格应在合理的范围内,避免出现异常值。 + +```json +{ + "metric_type": "column_value_between", + "config": { + "column": "price", + "min": 0, + "max": 1000000, + "filter": "status = 'ON_SALE'" + } +} +``` + +此配置将检查在售产品价格是否在0到100万之间,确保价格的合理性。 + +**章节来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) + +## 性能优化建议 + +1. **索引优化**:为经常检查的列创建适当的索引,特别是唯一性检查、非空检查和范围检查的列。 + +2. **分区策略**:对于大表,利用分区表特性,只检查最新分区的数据,减少扫描数据量。 + +3. **采样检查**:对于非关键性检查,可以采用采样方式,只检查部分数据以提高性能。 + +4. **缓存机制**:对于频繁执行且结果变化不大的检查,可以考虑结果缓存。 + +5. **批量处理**:将多个检查任务合并执行,减少数据库连接和查询开销。 + +6. **执行时间规划**:将资源密集型检查安排在业务低峰期执行。 + +7. **SQL优化**:定期审查生成的SQL语句,确保其执行计划最优。 + +8. **监控与告警**:建立检查任务的性能监控,及时发现和解决性能瓶颈。 + +**章节来源** +- 所有具体指标实现类 + +## 结论 + +DataVines提供了丰富且灵活的单表列级质量检查规则,通过统一的`SqlMetric`接口实现,具有良好的扩展性和可维护性。这些规则覆盖了数据质量的多个维度,包括完整性、有效性、一致性等,能够满足各种业务场景的需求。通过合理配置和性能优化,可以有效保障数据质量,为数据分析和决策提供可靠的数据基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\345\237\272\347\241\200\345\261\236\346\200\247\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\345\237\272\347\241\200\345\261\236\346\200\247\346\243\200\346\237\245.md" new file mode 100644 index 00000000..663f2ec1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\345\237\272\347\241\200\345\261\236\346\200\247\346\243\200\346\237\245.md" @@ -0,0 +1,280 @@ +# 基础属性检查 + + +**本文档引用的文件** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-length\src\main\java\io\datavines\metric\plugin\ColumnLength.java) +- [ColumnInEnums.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-in-enums\src\main\java\io\datavines\metric\plugin\ColumnInEnums.java) +- [ColumnMatchRegex.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-match-regex\src\main\java\io\datavines\metric\plugin\ColumnMatchRegex.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [ConfigItem.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ConfigItem.java) + + +## 目录 +1. [非空检查(ColumnNotNull)](#非空检查columnnotnull) +2. [唯一性检查(ColumnUnique)](#唯一性检查columnunique) +3. [长度检查(ColumnLength)](#长度检查columnlength) +4. [枚举值检查(ColumnInEnums)](#枚举值检查columninenums) +5. [正则匹配检查(ColumnMatchRegex)](#正则匹配检查columnmatchregex) +6. [规则实现与执行引擎集成](#规则实现与执行引擎集成) +7. [实际业务场景应用案例](#实际业务场景应用案例) + +## 非空检查(ColumnNotNull) + +非空检查(ColumnNotNull)是确保数据完整性的重要规则,用于验证指定列中是否存在空值。该规则通过检查列值是否为NULL或空字符串来保证数据的完整性。在DataVines中,`ColumnNotNull`类实现了这一功能,继承自`BaseSingleTableColumnNotUseView`基类。 + +该规则适用于数值类型、字符串类型和日期时间类型的数据。配置参数包括表名(table)、列名(column)和可选的过滤条件(filter)。当配置中包含列名时,系统会自动添加相应的过滤条件,确保只检查指定列的非空性。 + +**中文名称**: 非空检查 +**英文名称**: column_not_null +**质量维度**: 有效性(EFFECTIVENESS) +**适用数据类型**: 数值类型、字符串类型、日期时间类型 + +**配置参数说明**: +- `table`: 要检查的表名 +- `column`: 要检查的列名 +- `filter`: 可选的过滤条件,用于限定检查范围 + +**使用场景示例**: 用户表中的手机号字段必须非空,以确保能够联系到用户。 + +**性能优化建议**: 对于大表,建议在执行检查前对表进行分区或使用索引,以提高查询效率。 + +**本节来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java#L34-L71) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java#L27-L61) + +## 唯一性检查(ColumnUnique) + +唯一性检查(ColumnUnique)用于保证主键或业务键的唯一性,防止数据重复。该规则通过检查指定列中是否存在重复值来确保数据的唯一性。在DataVines中,`ColumnUnique`类实现了这一功能,同样继承自`BaseSingleTableColumnNotUseView`基类。 + +该规则适用于数值类型、字符串类型和日期时间类型的数据。配置参数包括表名(table)、列名(column)和可选的过滤条件(filter)。当配置中包含列名时,系统会生成相应的SQL查询,使用GROUP BY和HAVING子句来检测重复值。 + +**中文名称**: 唯一性检查 +**英文名称**: column_unique +**质量维度**: 唯一性(UNIQUENESS) +**适用数据类型**: 数值类型、字符串类型、日期时间类型 + +**配置参数说明**: +- `table`: 要检查的表名 +- `column`: 要检查的列名 +- `filter`: 可选的过滤条件,用于限定检查范围 + +**使用场景示例**: 订单表中的订单号必须唯一,以避免订单冲突。 + +**性能优化建议**: 对于大表,建议在执行检查前对相关列建立唯一索引,这不仅能提高检查效率,还能在数据插入时自动防止重复。 + +**本节来源** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java#L29-L79) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java#L27-L61) + +## 长度检查(ColumnLength) + +长度检查(ColumnLength)用于验证字段长度是否符合预定义的合规性要求。该规则通过比较字段的实际长度与预设长度来确保数据格式的正确性。在DataVines中,`ColumnLength`类实现了这一功能,继承自`BaseSingleTableColumnNotUseView`基类。 + +该规则主要适用于字符串类型和日期时间类型的数据。配置参数包括表名(table)、列名(column)、长度(length)和比较符(comparator)。比较符可以是等于、大于、小于等操作符,用于定义长度检查的具体条件。 + +**中文名称**: 长度检查 +**英文名称**: column_length +**质量维度**: 完整性(COMPLETENESS) +**适用数据类型**: 字符串类型、日期时间类型 + +**配置参数说明**: +- `table`: 要检查的表名 +- `column`: 要检查的列名 +- `length`: 预期的字段长度 +- `comparator`: 比较符,如"="、">"、"<"等 + +**使用场景示例**: 产品表中的产品名称字段长度应在1到100个字符之间。 + +**性能优化建议**: 对于频繁进行长度检查的字段,可以考虑在数据库层面设置字段长度限制,从而在数据写入时就进行验证。 + +**本节来源** +- [ColumnLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-length\src\main\java\io\datavines\metric\plugin\ColumnLength.java#L29-L79) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java#L27-L61) + +## 枚举值检查(ColumnInEnums) + +枚举值检查(ColumnInEnums)用于校验字段值是否在预定义的集合内。该规则通过检查字段值是否属于指定的枚举值列表来确保数据的有效性。在DataVines中,`ColumnInEnums`类实现了这一功能,继承自`BaseSingleTableColumnNotUseView`基类。 + +该规则适用于数值类型、字符串类型和日期时间类型的数据。配置参数包括表名(table)、列名(column)和枚举值列表(enum_list)。枚举值列表是一个逗号分隔的字符串,包含所有允许的值。 + +**中文名称**: 枚举值检查 +**英文名称**: column_in_enums +**质量维度**: 有效性(EFFECTIVENESS) +**适用数据类型**: 数值类型、字符串类型、日期时间类型 + +**配置参数说明**: +- `table`: 要检查的表名 +- `column`: 要检查的列名 +- `enum_list`: 允许的枚举值列表,以逗号分隔 + +**使用场景示例**: 产品表中的分类字段只能是"电子产品"、"服装"、"家居"等预定义的值。 + +**性能优化建议**: 对于包含大量枚举值的检查,可以考虑将枚举值存储在单独的参考表中,并使用JOIN操作进行检查,这样可以提高查询的可维护性和性能。 + +**本节来源** +- [ColumnInEnums.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-in-enums\src\main\java\io\datavines\metric\plugin\ColumnInEnums.java#L29-L74) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java#L27-L61) + +## 正则匹配检查(ColumnMatchRegex) + +正则匹配检查(ColumnMatchRegex)用于验证字段格式是否符合特定的模式,如邮箱、手机号等。该规则通过应用正则表达式来检查字段值的格式是否正确。在DataVines中,`ColumnMatchRegex`类实现了这一功能,继承自`BaseSingleTableColumnNotUseView`基类。 + +该规则主要适用于字符串类型和日期时间类型的数据。配置参数包括表名(table)、列名(column)和正则表达式(regexp)。正则表达式定义了字段值必须匹配的模式。 + +**中文名称**: 正则表达式[匹配]检查 +**英文名称**: column_match_regex +**质量维度**: 完整性(COMPLETENESS) +**适用数据类型**: 字符串类型、日期时间类型 + +**配置参数说明**: +- `table`: 要检查的表名 +- `column`: 要检查的列名 +- `regexp`: 用于验证字段格式的正则表达式 + +**使用场景示例**: 用户表中的邮箱字段必须符合标准的邮箱格式,如"username@domain.com"。 + +**性能优化建议**: 对于复杂的正则表达式,建议在执行检查前对数据进行预处理,如去除前后空格,以减少正则匹配的复杂度。同时,对于频繁检查的字段,可以考虑在应用层面进行格式验证,减少数据库层面的计算负担。 + +**本节来源** +- [ColumnMatchRegex.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-match-regex\src\main\java\io\datavines\metric\plugin\ColumnMatchRegex.java#L30-L76) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java#L27-L61) + +## 规则实现与执行引擎集成 + +DataVines的基础属性检查规则通过`SqlMetric`接口实现,并与执行引擎紧密集成。`SqlMetric`是一个SPI(Service Provider Interface)接口,定义了所有质量检查规则必须实现的方法,如获取规则名称、质量维度、生成SQL查询等。 + +每个具体的检查规则都实现了`SqlMetric`接口,并继承自`BaseSingleTable`或其子类。`BaseSingleTable`提供了通用的功能,如处理配置参数、生成基础SQL查询等。`BaseSingleTableColumnNotUseView`进一步扩展了这些功能,专门用于处理单表列级别的检查。 + +执行引擎通过`PluginLoader`加载相应的`SqlMetric`插件,并根据配置参数生成具体的SQL查询。这些查询被发送到目标数据源执行,结果返回给执行引擎进行处理和报告。 + +```mermaid +classDiagram +class SqlMetric { +<> ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++void prepare(Map~String,String~) +} +class BaseSingleTable { +-StringBuilder invalidateItemsSql +-String[] filters +-HashMap~String,ConfigItem~ configMap +-Set~String~ requiredOptions ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++void prepare(Map~String,String~) ++ConnectorFactory getConnectorFactory(Map~String,String~) +} +class BaseSingleTableColumnNotUseView { ++MetricLevel getLevel() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getDirectActualValue(Map~String,String~) +} +class ColumnNotNull { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++void prepare(Map~String,String~) +} +class ColumnUnique { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++void prepare(Map~String,String~) +} +class ColumnLength { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++void prepare(Map~String,String~) +} +class ColumnInEnums { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++void prepare(Map~String,String~) +} +class ColumnMatchRegex { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++void prepare(Map~String,String~) +} +SqlMetric <|-- BaseSingleTable +BaseSingleTable <|-- BaseSingleTableColumnNotUseView +BaseSingleTableColumnNotUseView <|-- ColumnNotNull +BaseSingleTableColumnNotUseView <|-- ColumnUnique +BaseSingleTableColumnNotUseView <|-- ColumnLength +BaseSingleTableColumnNotUseView <|-- ColumnInEnums +BaseSingleTableColumnNotUseView <|-- ColumnMatchRegex +``` + +**图示来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java#L28-L112) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L33-L100) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java#L27-L61) + +**本节来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java#L28-L112) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L33-L100) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java#L27-L61) + +## 实际业务场景应用案例 + +### 用户表手机号非空验证 + +在用户管理系统中,确保用户的手机号非空是非常重要的,因为手机号是联系用户的主要方式之一。通过配置`ColumnNotNull`规则,可以定期检查用户表中的手机号字段,确保没有空值。 + +**配置示例**: +```json +{ + "table": "users", + "column": "phone_number", + "filter": "status = 'active'" +} +``` + +这个配置会检查所有状态为"active"的用户,确保他们的手机号字段不为空。 + +### 订单表订单号唯一性校验 + +在电商系统中,订单号的唯一性至关重要,以避免订单冲突和重复。通过配置`ColumnUnique`规则,可以定期检查订单表中的订单号字段,确保没有重复值。 + +**配置示例**: +```json +{ + "table": "orders", + "column": "order_id", + "filter": "order_date >= '2023-01-01'" +} +``` + +这个配置会检查2023年1月1日以来的所有订单,确保订单号的唯一性。 + +### 产品表分类字段枚举值校验 + +在产品管理系统中,产品的分类应该限制在预定义的范围内,以保持数据的一致性和可管理性。通过配置`ColumnInEnums`规则,可以确保产品表中的分类字段只包含允许的值。 + +**配置示例**: +```json +{ + "table": "products", + "column": "category", + "enum_list": "电子产品,服装,家居,图书,食品" +} +``` + +这个配置会检查所有产品的分类字段,确保它们只包含预定义的五个类别之一。 + +**本节来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java#L34-L71) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java#L29-L79) +- [ColumnInEnums.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-in-enums\src\main\java\io\datavines\metric\plugin\ColumnInEnums.java#L29-L74) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\347\273\237\350\256\241\347\211\271\345\276\201\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\347\273\237\350\256\241\347\211\271\345\276\201\346\243\200\346\237\245.md" new file mode 100644 index 00000000..0553cd78 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245/\347\273\237\350\256\241\347\211\271\345\276\201\346\243\200\346\237\245.md" @@ -0,0 +1,293 @@ +# 统计特征检查 + + +**本文档引用的文件** +- [ColumnAvgLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg-length\src\main\java\io\datavines\metric\plugin\ColumnAvgLength.java) +- [ColumnStdDev.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-std-dev\src\main\java\io\datavines\metric\plugin\ColumnStdDev.java) +- [ColumnVariance.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-variance\src\main\java\io\datavines\metric\plugin\ColumnVariance.java) +- [BaseSingleTableColumn.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumn.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [DataVinesDataType.java](file://datavines-common\src\main\java\io\datavines\common\enums\DataVinesDataType.java) +- [ClickHouseMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-clickhouse\src\main\java\io\datavines\connector\plugin\ClickHouseMetricScript.java) +- [SparkDailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\SparkDailyAvg.java) +- [SparkWeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkWeeklyAvg.java) +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java) +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) +- [DiffPercentage.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff-percentage\src\main\java\io\datavines\metric\result\formula\DiffPercentage.java) + + +## 目录 +1. [引言](#引言) +2. [核心统计特征检查规则](#核心统计特征检查规则) +3. [平均长度检查(ColumnAvgLength)](#平均长度检查columnavglength) +4. [标准差检查(ColumnStdDev)](#标准差检查columnstddev) +5. [方差检查(ColumnVariance)](#方差检查columnvariance) +6. [预期值插件与趋势监控](#预期值插件与趋势监控) +7. [SQL聚合函数实现原理](#sql聚合函数实现原理) +8. [实际业务应用场景](#实际业务应用场景) +9. [性能优化建议](#性能优化建议) +10. [配置参数说明](#配置参数说明) + +## 引言 + +DataVines 是一个数据质量监控平台,支持多种单表列统计特征的质量检查规则。本文档重点介绍三种核心的统计特征检查:平均长度检查(ColumnAvgLength)、标准差检查(ColumnStdDev)和方差检查(ColumnVariance)。这些规则通过SQL聚合函数计算统计指标,并结合预期值插件进行趋势监控,帮助用户发现数据异常和质量问题。 + +**本文档引用的文件** +- [ColumnAvgLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg-length\src\main\java\io\datavines\metric\plugin\ColumnAvgLength.java) +- [ColumnStdDev.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-std-dev\src\main\java\io\datavines\metric\plugin\ColumnStdDev.java) +- [ColumnVariance.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-variance\src\main\java\io\datavines\metric\plugin\ColumnVariance.java) + +## 核心统计特征检查规则 + +DataVines的统计特征检查规则基于`SqlMetric`接口实现,所有规则都继承自`BaseSingleTableColumn`基类。这些规则通过SQL聚合函数计算统计指标,并将结果与预期值进行比较,以评估数据质量。 + +```mermaid +classDiagram +class SqlMetric { +<> ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++ExecuteSql getActualValue(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class BaseSingleTableColumn { ++Map~String, ConfigItem~ configMap ++Set~String~ requiredOptions ++void prepare(Map~String,String~ config) ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) +} +class ColumnAvgLength { ++String getName() ++String getZhName() ++DataVinesDataType[] suitableType() +} +class ColumnStdDev { ++String getName() ++String getZhName() ++DataVinesDataType[] suitableType() +} +class ColumnVariance { ++String getName() ++String getZhName() ++DataVinesDataType[] suitableType() +} +SqlMetric <|-- BaseSingleTableColumn +BaseSingleTableColumn <|-- ColumnAvgLength +BaseSingleTableColumn <|-- ColumnStdDev +BaseSingleTableColumn <|-- ColumnVariance +``` + +**图表来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTableColumn.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumn.java) +- [ColumnAvgLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg-length\src\main\java\io\datavines\metric\plugin\ColumnAvgLength.java) +- [ColumnStdDev.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-std-dev\src\main\java\io\datavines\metric\plugin\ColumnStdDev.java) +- [ColumnVariance.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-variance\src\main\java\io\datavines\metric\plugin\ColumnVariance.java) + +## 平均长度检查(ColumnAvgLength) + +平均长度检查用于分析文本字段的平均长度趋势,帮助监控文本数据的完整性。该规则适用于字符串、数值和日期时间类型的数据。 + +### 配置参数说明 + +| 参数 | 说明 | 必填 | +|------|------|------| +| column | 要检查的列名 | 是 | +| filters | 过滤条件,用于限定检查范围 | 否 | + +### 使用场景示例 + +- 监控用户评论的平均长度变化,确保用户输入内容的完整性 +- 检查产品描述字段的平均长度,防止描述过短影响用户体验 +- 跟踪日志消息的平均长度,及时发现异常日志模式 + +### 性能优化建议 + +- 对于大表,建议添加适当的过滤条件以减少计算量 +- 在高频率检查场景下,考虑使用采样策略 +- 确保被检查的列上有适当的索引以提高查询性能 + +**本文档引用的文件** +- [ColumnAvgLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg-length\src\main\java\io\datavines\metric\plugin\ColumnAvgLength.java) +- [DataVinesDataType.java](file://datavines-common\src\main\java\io\datavines\common\enums\DataVinesDataType.java) + +## 标准差检查(ColumnStdDev) + +标准差检查用于衡量数值字段的离散程度,反映数据的波动性。标准差越大,表示数据点越分散;标准差越小,表示数据点越集中。 + +### 配置参数说明 + +| 参数 | 说明 | 必填 | +|------|------|------| +| column | 要检查的列名 | 是 | +| filters | 过滤条件,用于限定检查范围 | 否 | + +### 使用场景示例 + +- 检测交易金额的异常波动,识别潜在的欺诈行为 +- 监控系统响应时间的标准差,评估系统稳定性 +- 分析用户活跃度指标的离散程度,识别用户行为模式变化 + +### 性能优化建议 + +- 对于大数据集,考虑使用近似算法计算标准差 +- 在实时监控场景下,可以采用滑动窗口计算标准差 +- 确保数值列的数据类型正确,避免类型转换开销 + +**本文档引用的文件** +- [ColumnStdDev.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-std-dev\src\main\java\io\datavines\metric\plugin\ColumnStdDev.java) +- [DataVinesDataType.java](file://datavines-common\src\main\java\io\datavines\common\enums\DataVinesDataType.java) + +## 方差检查(ColumnVariance) + +方差检查用于评估数据的波动性,是标准差的平方。方差越大,表示数据的离散程度越高;方差越小,表示数据越集中。 + +### 配置参数说明 + +| 参数 | 说明 | 必填 | +|------|------|------| +| column | 要检查的列名 | 是 | +| filters | 过滤条件,用于限定检查范围 | 否 | + +### 使用场景示例 + +- 评估投资组合的风险水平,方差越大风险越高 +- 监控生产过程中的质量指标方差,确保产品质量稳定 +- 分析网络流量的方差,检测潜在的DDoS攻击 + +### 性能优化建议 + +- 与标准差检查类似,考虑使用近似算法处理大数据集 +- 对于时间序列数据,可以结合移动方差进行趋势分析 +- 定期清理历史数据以保持计算效率 + +**本文档引用的文件** +- [ColumnVariance.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-variance\src\main\java\io\datavines\metric\plugin\ColumnVariance.java) +- [DataVinesDataType.java](file://datavines-common\src\main\java\io\datavines\common\enums\DataVinesDataType.java) + +## 预期值插件与趋势监控 + +DataVines提供多种预期值插件,用于与实际统计值进行比较,实现趋势监控。 + +### 预期值插件类型 + +| 插件 | 说明 | +|------|------| +| 固定值(FixValue) | 使用预设的固定值作为预期值 | +| 日均值(DailyAvg) | 使用历史日均值作为预期值 | +| 周均值(WeeklyAvg) | 使用历史周均值作为预期值 | +| 月均值(MonthlyAvg) | 使用历史月均值作为预期值 | + +### 趋势监控流程 + +```mermaid +flowchart TD +A[获取实际值] --> B[获取预期值] +B --> C[计算差异] +C --> D[应用结果公式] +D --> E[生成质量报告] +E --> F[触发告警如需要] +``` + +**图表来源** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) +- [SparkDailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\SparkDailyAvg.java) +- [SparkWeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkWeeklyAvg.java) +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java) + +## SQL聚合函数实现原理 + +统计特征检查通过SQL聚合函数计算实际值,不同数据库的实现可能略有差异。 + +### SQL实现示例 + +```mermaid +sequenceDiagram +participant 用户 as 用户界面 +participant 规则 as 统计规则 +participant 脚本 as MetricScript +participant 数据库 as 数据库 +用户->>规则 : 配置检查规则 +规则->>脚本 : 调用getActualValue() +脚本->>脚本 : 生成SQL模板 +脚本->>数据库 : 执行SQL查询 +数据库-->>脚本 : 返回结果 +脚本-->>规则 : 返回ExecuteSql +规则-->>用户 : 显示检查结果 +``` + +**图表来源** +- [ColumnAvgLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg-length\src\main\java\io\datavines\metric\plugin\ColumnAvgLength.java) +- [ClickHouseMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-clickhouse\src\main\java\io\datavines\connector\plugin\ClickHouseMetricScript.java) + +## 实际业务应用场景 + +### 用户评论平均长度监控 + +监控电商平台用户评论的平均长度变化,确保用户反馈的完整性。当平均长度显著下降时,可能表示用户参与度降低或存在刷评行为。 + +### 交易金额异常波动检测 + +通过标准差和方差检查金融交易金额的波动性。当方差突然增大时,可能表示存在异常交易模式,需要进一步调查。 + +### 系统性能指标监控 + +监控系统响应时间的标准差,评估系统稳定性。标准差持续增大可能表示系统负载不均衡或存在性能瓶颈。 + +**本文档引用的文件** +- [ColumnAvgLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg-length\src\main\java\io\datavines\metric\plugin\ColumnAvgLength.java) +- [ColumnStdDev.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-std-dev\src\main\java\io\datavines\metric\plugin\ColumnStdDev.java) +- [ColumnVariance.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-variance\src\main\java\io\datavines\metric\plugin\ColumnVariance.java) + +## 性能优化建议 + +1. **索引优化**:确保被检查的列上有适当的索引,特别是对于大表的统计计算。 +2. **采样策略**:对于超大数据集,考虑使用随机采样来估算统计指标。 +3. **分区查询**:利用表分区特性,只查询相关分区的数据以提高效率。 +4. **缓存机制**:对于频繁查询的统计结果,考虑使用缓存减少重复计算。 +5. **并行处理**:在支持的数据库中,启用并行查询以加速大表的统计计算。 + +**本文档引用的文件** +- [ColumnAvgLength.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg-length\src\main\java\io\datavines\metric\plugin\ColumnAvgLength.java) +- [ColumnStdDev.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-std-dev\src\main\java\io\datavines\metric\plugin\ColumnStdDev.java) +- [ColumnVariance.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-variance\src\main\java\io\datavines\metric\plugin\ColumnVariance.java) + +## 配置参数说明 + +### 通用配置参数 + +| 参数 | 说明 | 类型 | 必填 | +|------|------|------|------| +| column | 要检查的列名 | 字符串 | 是 | +| filters | SQL WHERE子句条件 | 字符串 | 否 | +| result_formula | 结果计算公式 | 枚举 | 否 | + +### 结果公式类型 + +| 公式 | 说明 | 计算方式 | +|------|------|------| +| diff | 差值 | \|实际值 - 期望值\| | +| percentage | 百分比 | 实际值/期望值×100% | +| diff_percentage | 差异百分比 | \|实际值-期望值\|/期望值×100% | + +```mermaid +erDiagram +METRIC_RULE ||--o{ RESULT_FORMULA : "使用" +METRIC_RULE { +string name +string column +string filters +string result_formula +} +RESULT_FORMULA { +string name +string description +string calculation_method +} +``` + +**图表来源** +- [DiffPercentage.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff-percentage\src\main\java\io\datavines\metric\result\formula\DiffPercentage.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\346\243\200\346\237\245\350\247\204\345\210\231.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\346\243\200\346\237\245\350\247\204\345\210\231.md" new file mode 100644 index 00000000..acabd669 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\346\243\200\346\237\245\350\247\204\345\210\231.md" @@ -0,0 +1,248 @@ +# 检查规则 + + +**本文档中引用的文件** +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ColumnNotNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-not-null/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java) +- [ColumnUnique.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-unique/src/main/java/io/datavines/metric/plugin/ColumnUnique.java) +- [ColumnValueBetween.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-value-between/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java) +- [ColumnMatchRegex.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-match-regex/src/main/java/io/datavines/metric/plugin/ColumnMatchRegex.java) +- [ColumnInEnums.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-in-enums/src/main/java/io/datavines/metric/plugin/ColumnInEnums.java) +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) +- [MultiTableValueComparison.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-value-comparison/src/main/java/io/datavines/metric/plugin/MultiTableValueComparison.java) +- [BaseSingleTableColumn.java](file://datavines-metric/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumn.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) + + +## 目录 +1. [引言](#引言) +2. [检查规则分类](#检查规则分类) +3. [单表列检查规则](#单表列检查规则) +4. [自定义SQL检查规则](#自定义sql检查规则) +5. [跨表检查规则](#跨表检查规则) +6. [规则配置与使用场景](#规则配置与使用场景) +7. [规则组合与优先级](#规则组合与优先级) +8. [性能优化建议](#性能优化建议) +9. [结论](#结论) + +## 引言 +DataVines 是一个数据质量检查平台,提供了27种内置的检查规则,用于确保数据的准确性、完整性和一致性。这些规则分为三大类:单表列检查、自定义SQL检查和跨表检查。本文档详细描述了这些规则的实现原理、使用场景、配置示例和性能优化建议。 + +**检查规则分类** +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java#L24-L34) + +## 检查规则分类 +DataVines的检查规则主要分为以下三类: +1. **单表列检查**:针对单个表的列进行数据质量检查,包括非空检查、唯一性检查、值范围检查等。 +2. **自定义SQL检查**:通过自定义聚合SQL实现复杂业务规则的验证。 +3. **跨表检查**:在多个表之间进行数据准确性检查和值比较。 + +```mermaid +graph TD +A[检查规则] --> B[单表列检查] +A --> C[自定义SQL检查] +A --> D[跨表检查] +B --> B1[非空检查] +B --> B2[唯一性检查] +B --> B3[值范围检查] +B --> B4[正则匹配检查] +B --> B5[枚举值检查] +B --> B6[数据类型检查] +C --> C1[自定义聚合SQL] +D --> D1[跨表准确性检查] +D --> D2[两表值比较检查] +``` + +**Diagram sources** +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java#L24-L34) + +**Section sources** +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java#L24-L34) + +## 单表列检查规则 +单表列检查规则用于验证单个表中列的数据质量。这些规则通过SQL查询实现,检查结果可以用于评估数据的完整性、一致性和准确性。 + +### 非空检查 +非空检查用于验证指定列中是否存在空值。该规则通过`COUNT`函数和`IS NULL`条件实现。 + +**实现原理**: +- 查询指定列中空值的数量。 +- 如果空值数量大于0,则检查失败。 + +**使用场景**: +- 确保关键字段(如用户ID、订单号)不为空。 +- 验证数据导入过程中是否有缺失值。 + +**Section sources** +- [ColumnNotNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-not-null/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java) + +### 唯一性检查 +唯一性检查用于验证指定列中的值是否唯一。该规则通过`COUNT`和`GROUP BY`实现。 + +**实现原理**: +- 查询指定列中重复值的数量。 +- 如果重复值数量大于0,则检查失败。 + +**使用场景**: +- 确保主键字段的唯一性。 +- 验证业务唯一标识符(如身份证号、手机号)的唯一性。 + +**Section sources** +- [ColumnUnique.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-unique/src/main/java/io/datavines/metric/plugin/ColumnUnique.java) + +### 值范围检查 +值范围检查用于验证指定列中的值是否在预定义的范围内。该规则通过`BETWEEN`或比较操作符实现。 + +**实现原理**: +- 查询指定列中超出范围的值的数量。 +- 如果超出范围的值数量大于0,则检查失败。 + +**使用场景**: +- 验证年龄、价格等数值字段的合理性。 +- 确保时间字段在有效范围内。 + +**Section sources** +- [ColumnValueBetween.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-value-between/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java) + +### 正则匹配检查 +正则匹配检查用于验证指定列中的值是否符合预定义的正则表达式模式。该规则通过`REGEXP`或类似函数实现。 + +**实现原理**: +- 查询指定列中不符合正则表达式的值的数量。 +- 如果不符合的值数量大于0,则检查失败。 + +**使用场景**: +- 验证邮箱、电话号码等格式的正确性。 +- 确保数据符合特定的格式要求。 + +**Section sources** +- [ColumnMatchRegex.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-match-regex/src/main/java/io/datavines/metric/plugin/ColumnMatchRegex.java) + +### 枚举值检查 +枚举值检查用于验证指定列中的值是否在预定义的枚举值列表中。该规则通过`IN`操作符实现。 + +**实现原理**: +- 查询指定列中不在枚举值列表中的值的数量。 +- 如果不在列表中的值数量大于0,则检查失败。 + +**使用场景**: +- 验证状态字段(如订单状态、用户状态)的合法性。 +- 确保数据符合预定义的业务规则。 + +**Section sources** +- [ColumnInEnums.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-in-enums/src/main/java/io/datavines/metric/plugin/ColumnInEnums.java) + +### 数据类型检查 +数据类型检查用于验证指定列中的值是否符合预定义的数据类型。该规则通过类型转换和异常处理实现。 + +**实现原理**: +- 尝试将指定列中的值转换为预定义的数据类型。 +- 如果转换失败,则检查失败。 + +**使用场景**: +- 验证数值字段是否为有效数字。 +- 确保日期字段为有效日期格式。 + +**Section sources** +- [BaseSingleTableColumn.java](file://datavines-metric/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumn.java) + +## 自定义SQL检查规则 +自定义SQL检查规则允许用户通过编写自定义聚合SQL来实现复杂的业务规则验证。 + +### 实现机制 +- 用户提供自定义SQL查询。 +- 系统执行SQL查询并获取结果。 +- 根据预定义的阈值和预期结果进行比较。 + +**使用场景**: +- 验证复杂的业务逻辑,如订单总额与明细总额的一致性。 +- 实现特定的统计指标计算。 + +**Section sources** +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) + +## 跨表检查规则 +跨表检查规则用于在多个表之间进行数据质量检查,确保数据的一致性和准确性。 + +### 跨表准确性检查 +跨表准确性检查用于验证两个表之间的数据是否一致。该规则通过`JOIN`操作和比较实现。 + +**实现原理**: +- 将两个表进行`JOIN`操作。 +- 比较关键字段的值是否一致。 +- 如果不一致的记录数量大于0,则检查失败。 + +**使用场景**: +- 验证源表和目标表之间的数据一致性。 +- 确保数据迁移或同步过程中的数据完整性。 + +**Section sources** +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) + +### 两表值比较检查 +两表值比较检查用于比较两个表中特定字段的聚合值。该规则通过`SUM`、`COUNT`等聚合函数实现。 + +**实现原理**: +- 分别计算两个表中指定字段的聚合值。 +- 比较两个聚合值是否在预定义的阈值范围内。 +- 如果差异超出阈值,则检查失败。 + +**使用场景**: +- 验证订单表和支付表的总金额是否一致。 +- 确保统计报表数据的准确性。 + +**Section sources** +- [MultiTableValueComparison.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-value-comparison/src/main/java/io/datavines/metric/plugin/MultiTableValueComparison.java) + +## 规则配置与使用场景 +每种检查规则都支持详细的配置,包括参数设置、阈值配置和预期结果定义。 + +### 参数设置 +- **列名**:指定要检查的列。 +- **阈值**:定义检查通过的阈值。 +- **预期结果**:定义期望的检查结果。 + +### 阈值配置 +- **绝对阈值**:指定具体的数值阈值。 +- **相对阈值**:指定相对于某个基准的百分比阈值。 + +### 预期结果定义 +- **固定值**:预期结果为固定值。 +- **动态计算**:预期结果通过其他规则或SQL查询动态计算。 + +**Section sources** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) + +## 规则组合与优先级 +DataVines支持规则的组合使用和优先级处理,以满足复杂的业务需求。 + +### 组合使用方式 +- **AND组合**:所有规则都必须通过。 +- **OR组合**:至少一个规则通过。 +- **嵌套组合**:支持复杂的逻辑嵌套。 + +### 优先级处理机制 +- **高优先级规则**:优先执行,结果直接影响最终检查结果。 +- **低优先级规则**:在高优先级规则通过后执行。 + +**Section sources** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) + +## 性能优化建议 +为了提高检查规则的执行效率,建议采取以下优化措施: + +### 避免全表扫描 +- **索引优化**:为检查列创建适当的索引。 +- **分区表**:使用分区表减少扫描范围。 + +### 优化复杂规则执行效率 +- **缓存结果**:对频繁使用的查询结果进行缓存。 +- **并行执行**:将独立的检查规则并行执行。 + +**Section sources** +- [BaseSingleTableColumn.java](file://datavines-metric/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumn.java) + +## 结论 +DataVines提供的27种内置检查规则覆盖了数据质量检查的各个方面,从简单的非空检查到复杂的跨表比较。通过合理的配置和优化,可以有效提升数据质量,确保业务数据的准确性和一致性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\207\252\345\256\232\344\271\211SQL\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\207\252\345\256\232\344\271\211SQL\346\243\200\346\237\245.md" new file mode 100644 index 00000000..7c6be626 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\207\252\345\256\232\344\271\211SQL\346\243\200\346\237\245.md" @@ -0,0 +1,384 @@ +# 自定义SQL检查 + + +**本文档引用的文件** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [ExecuteSql.java](file://datavines-common\src\main\java\io\datavines\common\entity\ExecuteSql.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) +- [CommonConstants.java](file://datavines-common\src\main\java\io\datavines\common\CommonConstants.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) + + +## 目录 +1. [简介](#简介) +2. [自定义聚合SQL规则实现机制](#自定义聚合sql规则实现机制) +3. [配置参数说明](#配置参数说明) +4. [SQL执行与结果验证流程](#sql执行与结果验证流程) +5. [实际应用案例](#实际应用案例) +6. [SQL注入防护与执行安全控制](#sql注入防护与执行安全控制) +7. [性能优化建议](#性能优化建议) +8. [与其他内置规则的组合使用](#与其他内置规则的组合使用) + +## 简介 +自定义SQL检查功能允许用户通过编写自定义的聚合SQL语句来实现复杂的业务规则验证。该功能基于`CustomAggregateSql`规则实现,通过`SqlMetric`接口执行用户提供的SQL语句并验证结果。本文档详细说明了自定义SQL检查的实现机制、配置参数、执行流程、安全控制和性能优化等方面的内容。 + +## 自定义聚合SQL规则实现机制 + +`CustomAggregateSql`类实现了`SqlMetric`接口,提供了自定义聚合SQL检查的核心功能。该规则允许用户通过编写自定义的SQL语句来计算实际值,并与预期值进行比较,从而验证数据质量。 + +```mermaid +classDiagram +class SqlMetric { +<> ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++CheckResult validateConfig(Map config) ++Map getConfigMap() ++void prepare(Map config) ++ExecuteSql getInvalidateItems(Map inputParameter) ++ExecuteSql getActualValue(Map inputParameter) ++List suitableType() ++boolean isCustomSql() +} +class CustomAggregateSql { +-Set requiredOptions +-HashMap configMap ++CustomAggregateSql() ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++CheckResult validateConfig(Map config) ++Map getConfigMap() ++void prepare(Map config) ++ExecuteSql getInvalidateItems(Map inputParameter) ++ExecuteSql getActualValue(Map inputParameter) ++List suitableType() ++boolean isCustomSql() +} +class ExecuteSql { +-String sql +-String resultTable +-boolean isErrorOutput ++ExecuteSql(String sql, String resultTable) +} +SqlMetric <|-- CustomAggregateSql +CustomAggregateSql --> ExecuteSql : "返回" +``` + +**图源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [ExecuteSql.java](file://datavines-common\src\main\java\io\datavines\common\entity\ExecuteSql.java) + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java#L35-L117) + +## 配置参数说明 + +### 核心配置参数 +`CustomAggregateSql`规则的核心配置参数如下: + +| 参数名称 | 参数描述 | 是否必填 | 参数示例 | +|---------|--------|--------|--------| +| actual_aggregate_sql | 自定义聚合SQL语句 | 是 | SELECT SUM(order_amount) as actual_value FROM orders WHERE order_date = '${date}' | +| table | 目标表名 | 否 | orders | + +### SQL语句编写规范 +1. SQL语句必须包含聚合函数(如SUM、AVG、COUNT等) +2. 建议为聚合结果指定别名`as actual_value` +3. 可以使用参数占位符`${parameter_name}`来引用外部参数 +4. SQL语句应尽量简洁高效,避免全表扫描 + +### 参数占位符使用 +系统支持在SQL语句中使用参数占位符,这些占位符会在执行时被实际值替换。常用的占位符包括: + +- `${table}`:目标表名 +- `${date}`:日期参数 +- `${metric_unique_key}`:指标唯一键 +- `${database}`:数据库名 + +### 结果提取规则 +执行结果的提取遵循以下规则: +1. 系统会自动将`as actual_value`替换为`as actual_value_${metric_unique_key}`,以确保结果列名的唯一性 +2. 执行结果必须返回单个数值,该数值将作为实际值用于后续的验证 +3. 如果SQL语句返回多行或多列,系统将只取第一行第一列的值作为实际值 + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java#L41-L46) +- [CommonConstants.java](file://datavines-common\src\main\java\io\datavines\common\CommonConstants.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) + +## SQL执行与结果验证流程 + +### 执行流程概述 +自定义SQL检查的执行流程如下: + +```mermaid +flowchart TD +Start([开始]) --> ValidateConfig["验证配置参数"] +ValidateConfig --> ConfigValid{"配置有效?"} +ConfigValid --> |否| ReturnError["返回配置错误"] +ConfigValid --> |是| Prepare["准备执行环境"] +Prepare --> BuildSql["构建SQL语句"] +BuildSql --> ExecuteSql["执行SQL查询"] +ExecuteSql --> GetResult{"查询成功?"} +GetResult --> |否| HandleError["处理执行错误"] +GetResult --> |是| ExtractValue["提取实际值"] +ExtractValue --> ValidateResult["验证结果"] +ValidateResult --> End([结束]) +HandleError --> End +ReturnError --> End +``` + +**图源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java#L94-L106) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java#L175-L185) + +### 详细执行步骤 +1. **配置验证**:系统首先调用`validateConfig`方法验证用户提供的配置参数是否完整有效 +2. **环境准备**:调用`prepare`方法准备执行环境,此方法在`CustomAggregateSql`中为空实现 +3. **SQL构建**:从配置中获取`actual_aggregate_sql`参数值,并进行必要的处理 +4. **SQL执行**:使用JDBC连接执行构建好的SQL语句 +5. **结果提取**:从查询结果中提取实际值 +6. **结果验证**:将实际值与预期值进行比较,生成验证结果 + +### 结果处理机制 +系统通过`ExecuteSql`类封装SQL执行的相关信息: + +```java +public class ExecuteSql { + private String sql; + private String resultTable; + private boolean isErrorOutput; + + public ExecuteSql(String sql, String resultTable) { + this.sql = sql; + this.resultTable = resultTable; + } + + // getters and setters +} +``` + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java#L94-L106) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java#L175-L185) +- [ExecuteSql.java](file://datavines-common\src\main\java\io\datavines\common\entity\ExecuteSql.java) + +## 实际应用案例 + +### 案例1:验证每日订单总额是否在合理范围 +```sql +SELECT SUM(order_amount) as actual_value +FROM orders +WHERE order_date = '${current_date}' +``` + +此SQL语句用于计算指定日期的订单总额,系统会将计算结果与预期值(如前7天平均订单总额)进行比较,验证当日订单总额是否在合理范围内。 + +### 案例2:检查用户活跃度指标是否异常 +```sql +SELECT COUNT(DISTINCT user_id) as actual_value +FROM user_activity +WHERE activity_date = '${current_date}' +AND activity_type IN ('login', 'purchase', 'comment') +``` + +此SQL语句用于计算指定日期的活跃用户数,通过与历史数据对比,可以及时发现用户活跃度的异常波动。 + +### 案例3:验证库存周转率是否符合预期 +```sql +SELECT + SUM(sales_amount) / AVG(inventory_value) as actual_value +FROM + sales s, inventory i +WHERE + s.product_id = i.product_id + AND s.sale_date BETWEEN '${start_date}' AND '${end_date}' +``` + +此SQL语句计算指定时间段内的库存周转率,用于监控库存管理效率。 + +### 案例4:验证数据完整性 +```sql +SELECT + COUNT(*) as total_count, + COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed_count, + COUNT(CASE WHEN status = 'completed' THEN 1 END) * 1.0 / COUNT(*) as completion_rate +FROM orders +WHERE order_date = '${current_date}' +``` + +此SQL语句不仅计算订单总数,还计算完成订单的比例,用于全面评估数据完整性。 + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) + +## SQL注入防护与执行安全控制 + +### SQL注入防护机制 +系统通过以下方式防止SQL注入攻击: + +1. **参数化查询**:虽然自定义SQL直接拼接,但系统会对用户输入进行严格验证 +2. **输入验证**:在`validateConfig`方法中验证配置参数的合法性 +3. **关键字过滤**:对SQL语句中的危险关键字进行检测和过滤 +4. **执行权限控制**:限制SQL执行用户的数据库权限,仅授予必要的读取权限 + +### 执行安全控制 +系统实施了多层次的执行安全控制: + +```mermaid +flowchart TD +Start([SQL执行请求]) --> AuthCheck["身份验证"] +AuthCheck --> AuthValid{"验证通过?"} +AuthValid --> |否| Reject["拒绝请求"] +AuthValid --> |是| PermCheck["权限检查"] +PermCheck --> PermValid{"有执行权限?"} +PermValid --> |否| Reject +PermValid --> |是| SqlCheck["SQL语句检查"] +SqlCheck --> SqlValid{"SQL安全?"} +SqlValid --> |否| Reject +SqlValid --> |是| ExecSql["执行SQL"] +ExecSql --> Log["记录执行日志"] +Log --> ReturnResult["返回结果"] +Reject --> ReturnError["返回错误"] +ReturnError --> End([结束]) +ReturnResult --> End +``` + +**图源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java#L75-L77) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) + +### 安全最佳实践 +1. **最小权限原则**:为SQL执行用户分配最小必要的数据库权限 +2. **执行时间限制**:设置SQL执行的超时时间,防止长时间运行的查询影响系统性能 +3. **结果集大小限制**:限制返回结果集的大小,防止大量数据传输 +4. **审计日志**:记录所有SQL执行的详细信息,包括执行时间、执行用户、SQL语句等 + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java#L75-L77) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) + +## 性能优化建议 + +### 编写高效的聚合查询 +1. **使用适当的聚合函数**:根据业务需求选择最合适的聚合函数 +2. **添加必要的WHERE条件**:通过WHERE子句过滤数据,减少参与聚合的数据量 +3. **避免在聚合函数中使用复杂表达式**:复杂的表达式会增加计算开销 +4. **合理使用GROUP BY**:如果需要分组聚合,确保GROUP BY的列上有适当的索引 + +### 避免全表扫描 +1. **确保过滤条件列有索引**:为WHERE子句中使用的列创建索引 +2. **使用分区表**:对于大表,使用分区表可以显著提高查询性能 +3. **限制查询范围**:通过时间范围等条件限制查询的数据量 +4. **避免SELECT ***:只选择需要的列,减少I/O开销 + +### 利用索引优化 +```mermaid +erDiagram +ORDERS { +string order_id PK +date order_date FK +string customer_id FK +decimal order_amount +string status +} +CUSTOMERS { +string customer_id PK +string name +string email +date created_date +} +ORDER_ITEMS { +string item_id PK +string order_id FK +string product_id FK +int quantity +decimal price +} +ORDERS ||--o{ ORDER_ITEMS : "包含" +CUSTOMERS ||--o{ ORDERS : "下单" +note left of ORDERS +索引建议: +- order_date: 日期范围查询 +- customer_id: 客户相关查询 +- status: 状态过滤 +end note +note right of ORDER_ITEMS +索引建议: +- order_id: 订单详情查询 +- product_id: 产品销售统计 +end note +``` + +**图源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) + +### 查询性能监控 +1. **执行计划分析**:定期分析重要查询的执行计划,确保使用了最优的执行路径 +2. **性能基准测试**:建立查询性能基准,及时发现性能退化 +3. **慢查询监控**:设置慢查询阈值,监控和优化执行时间过长的查询 +4. **资源使用监控**:监控查询对CPU、内存、I/O等资源的使用情况 + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) + +## 与其他内置规则的组合使用 + +### 组合使用场景 +自定义SQL检查可以与其他内置规则组合使用,实现更复杂的数据质量验证: + +```mermaid +flowchart TD +subgraph "数据质量验证流程" +CustomSql["自定义SQL检查\n计算复杂指标"] +BuiltIn1["内置规则1\n基础数据检查"] +BuiltIn2["内置规则2\n数据一致性检查"] +BuiltIn3["内置规则3\n数据完整性检查"] +CustomSql --> Validation["结果验证"] +BuiltIn1 --> Validation +BuiltIn2 --> Validation +BuiltIn3 --> Validation +Validation --> Report["生成质量报告"] +end +subgraph "规则执行顺序" +Order1["1. 内置规则执行"] +Order2["2. 自定义SQL执行"] +Order3["3. 综合结果分析"] +Order1 --> Order2 --> Order3 +end +CustomSql -.-> Order2 +BuiltIn1 -.-> Order1 +BuiltIn2 -.-> Order1 +BuiltIn3 -.-> Order1 +Validation -.-> Order3 +``` + +**图源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) + +### 组合使用方式 +1. **并行执行**:自定义SQL检查与其他内置规则可以并行执行,提高整体验证效率 +2. **结果关联**:将自定义SQL检查的结果与其他规则的结果进行关联分析 +3. **条件触发**:根据内置规则的执行结果决定是否执行自定义SQL检查 +4. **综合评分**:将各类规则的验证结果综合计算,生成整体数据质量评分 + +### 典型组合案例 +1. **基础检查+复杂业务规则**:先执行字段非空、唯一性等基础检查,再执行自定义SQL进行复杂业务规则验证 +2. **数据完整性+业务指标**:先验证数据完整性,再通过自定义SQL计算关键业务指标 +3. **一致性检查+趋势分析**:先检查数据一致性,再通过自定义SQL进行趋势分析和异常检测 + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245/\344\270\244\350\241\250\345\200\274\346\257\224\350\276\203\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245/\344\270\244\350\241\250\345\200\274\346\257\224\350\276\203\346\243\200\346\237\245.md" new file mode 100644 index 00000000..d780340e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245/\344\270\244\350\241\250\345\200\274\346\257\224\350\276\203\346\243\200\346\237\245.md" @@ -0,0 +1,310 @@ +# 两表值比较检查 + + +**本文档引用的文件** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java) +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java) +- [FlinkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-config\src\main\java\io\datavines\engine\flink\config\FlinkMultiTableValueComparisonMetricBuilder.java) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [CommonConstants.java](file://datavines-common\src\main\java\io\datavines\common\CommonConstants.java) +- [RuleSelect/index.tsx](file://datavines-ui\Editor\components\MetricModal\RuleSelect\index.tsx) +- [MetricType.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\MetricType.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [配置参数详解](#配置参数详解) +4. [实现原理](#实现原理) +5. [使用场景与配置示例](#使用场景与配置示例) +6. [性能优化策略](#性能优化策略) +7. [常见问题与解决方案](#常见问题与解决方案) +8. [结论](#结论) + +## 简介 +两表值比较检查(MultiTableValueComparison)是DataVines数据质量框架中的一个重要功能,用于验证两个不同表中具有相同业务含义的字段在数值上的一致性。该功能特别适用于ETL过程中的数据转换验证、不同业务系统间关键指标的核对等场景。通过比较源系统和目标系统中的金额字段等关键数值,确保数据在迁移或处理过程中的准确性。 + +## 核心组件 + +两表值比较检查功能由多个核心组件构成,包括度量指标实现、配置构建器和用户界面组件。`MultiTableValueComparison`类是该功能的核心实现,实现了`SqlMetric`接口,定义了度量的基本属性和行为。该类位于`datavines-metric-plugins`模块中,负责定义度量的名称、维度和类型等元数据。 + +```mermaid +classDiagram +class SqlMetric { +<> ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++CheckResult validateConfig(Map~String,Object~) ++Map~String,ConfigItem~ getConfigMap() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class MultiTableValueComparison { +-String name +-String zhName +-MetricDimension dimension +-MetricType type ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++CheckResult validateConfig(Map~String,Object~) ++Map~String,ConfigItem~ getConfigMap() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class BaseLocalConfigurationBuilder { +<> ++void buildTransformConfigs() ++void buildSinkConfigs() +} +class BaseFlinkConfigurationBuilder { +<> ++void buildTransformConfigs() ++void buildSinkConfigs() +} +class BaseSparkConfigurationBuilder { +<> ++void buildTransformConfigs() ++void buildSinkConfigs() +} +class LocalMultiTableValueComparisonMetricBuilder { ++void buildTransformConfigs() ++void buildSinkConfigs() +} +class FlinkMultiTableValueComparisonMetricBuilder { ++void buildTransformConfigs() ++void buildSinkConfigs() +} +class SparkMultiTableValueComparisonMetricBuilder { ++void buildTransformConfigs() ++void buildSinkConfigs() +} +SqlMetric <|-- MultiTableValueComparison +BaseLocalConfigurationBuilder <|-- LocalMultiTableValueComparisonMetricBuilder +BaseFlinkConfigurationBuilder <|-- FlinkMultiTableValueComparisonMetricBuilder +BaseSparkConfigurationBuilder <|-- SparkMultiTableValueComparisonMetricBuilder +``` + +**图源** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java) +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java) +- [FlinkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-config\src\main\java\io\datavines\engine\flink\config\FlinkMultiTableValueComparisonMetricBuilder.java) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java) + +**章节源** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java#L31-L87) +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L45-L141) +- [FlinkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-config\src\main\java\io\datavines\engine\flink\config\FlinkMultiTableValueComparisonMetricBuilder.java#L31-L76) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java#L31-L76) + +## 配置参数详解 + +两表值比较检查功能提供了丰富的配置参数,以满足不同场景下的需求。主要配置参数包括两个表的连接信息、用于比较的字段选择、容差阈值设置等。 + +### 基本配置参数 + +| 参数名称 | 参数说明 | 配置来源 | +|--------|--------|--------| +| `table` | 源表名称 | ConfigConstants.TABLE | +| `table2` | 目标表名称 | CommonConstants.TABLE2 | +| `datasource_id` | 源数据源ID | ConfigConstants.DATASOURCE_ID | +| `target_datasource_id` | 目标数据源ID | ConfigConstants.TARGET_DATASOURCE_ID | +| `actual_execute_sql` | 源表实际值查询SQL | ConfigConstants.ACTUAL_EXECUTE_SQL | +| `expected_execute_sql` | 目标表期望值查询SQL | ConfigConstants.EXPECTED_EXECUTE_SQL | +| `threshold` | 容差阈值 | ConfigConstants.THRESHOLD | +| `result_formula` | 结果计算公式 | ConfigConstants.RESULT_FORMULA | + +### 高级配置参数 + +| 参数名称 | 参数说明 | 配置来源 | +|--------|--------|--------| +| `mappingColumns` | 字段映射关系 | ConfigConstants.MAPPING_COLUMNS | +| `on_clause` | 表连接条件 | ConfigConstants.ON_CLAUSE | +| `where_clause` | 查询过滤条件 | ConfigConstants.WHERE_CLAUSE | +| `failure_strategy` | 失败处理策略 | ConfigConstants.FAILURE_STRATEGY | +| `data_time` | 数据时间 | ConfigConstants.DATA_TIME | + +**章节源** +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java#L20-L183) +- [CommonConstants.java](file://datavines-common\src\main\java\io\datavines\common\CommonConstants.java#L177-L180) + +## 实现原理 + +两表值比较检查的实现原理主要包括数据抽取、字段映射、数值计算和差异判断等步骤。系统首先从两个不同的数据源中抽取数据,然后根据配置的字段映射关系进行数据对齐,最后计算数值差异并判断是否在允许的容差范围内。 + +```mermaid +sequenceDiagram +participant UI as 用户界面 +participant Server as 服务端 +participant Engine as 执行引擎 +participant SourceDB as 源数据库 +participant TargetDB as 目标数据库 +UI->>Server : 提交两表值比较检查配置 +Server->>Engine : 构建执行计划 +Engine->>SourceDB : 执行actual_execute_sql查询 +SourceDB-->>Engine : 返回实际值结果 +Engine->>TargetDB : 执行expected_execute_sql查询 +TargetDB-->>Engine : 返回期望值结果 +Engine->>Engine : 计算数值差异 +Engine->>Engine : 判断差异是否在阈值范围内 +Engine-->>Server : 返回检查结果 +Server-->>UI : 显示检查结果和差异报告 +Note over Engine,Engine : 根据result_formula配置
计算实际值与期望值的差异 +``` + +**图源** +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L48-L84) +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java#L31-L87) + +**章节源** +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L48-L84) +- [FlinkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-config\src\main\java\io\datavines\engine\flink\config\FlinkMultiTableValueComparisonMetricBuilder.java#L34-L51) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java#L34-L51) + +## 使用场景与配置示例 + +### ETL过程中的数据转换验证 + +在ETL(Extract, Transform, Load)过程中,数据从源系统抽取后经过转换加载到目标系统。两表值比较检查可以用于验证转换前后的数据一致性,确保关键业务指标在转换过程中没有发生意外变化。 + +```json +{ + "metric_type": "multi_table_value_comparison", + "metric_parameter": { + "datasource_id": "source_datasource_001", + "table": "sales_fact", + "actual_execute_sql": "SELECT SUM(amount) as actual_value FROM sales_fact WHERE date = '${system.biz.date}'", + "target_datasource_id": "target_datasource_001", + "table2": "sales_fact_dw", + "expected_execute_sql": "SELECT SUM(amount) as expected_value FROM sales_fact_dw WHERE date = '${system.biz.date}'", + "threshold": "0.01", + "result_formula": "diff_percentage" + } +} +``` + +### 不同业务系统间关键指标核对 + +当企业有多个业务系统(如ERP、CRM、财务系统)时,可以通过两表值比较检查来核对各系统间的关键业务指标是否一致,及时发现数据不一致问题。 + +```json +{ + "metric_type": "multi_table_value_comparison", + "metric_parameter": { + "datasource_id": "erp_datasource", + "table": "order_header", + "actual_execute_sql": "SELECT COUNT(*) as actual_value FROM order_header WHERE order_date = '${system.biz.date}' AND status = 'COMPLETED'", + "target_datasource_id": "crm_datasource", + "table2": "customer_order", + "expected_execute_sql": "SELECT COUNT(*) as expected_value FROM customer_order WHERE order_date = '${system.biz.date}' AND status = 'SHIPPED'", + "threshold": "0", + "result_formula": "diff" + } +} +``` + +**章节源** +- [RuleSelect/index.tsx](file://datavines-ui\Editor\components\MetricModal\RuleSelect\index.tsx#L371-L394) +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L86-L102) + +## 性能优化策略 + +### 时间范围过滤减少数据量 + +在配置查询SQL时,应尽量使用时间范围过滤条件,避免全表扫描。可以利用DataVines提供的系统参数(如`${system.biz.date}`)来动态指定查询的时间范围。 + +```mermaid +flowchart TD +Start([开始]) --> FilterByTime["按时间范围过滤数据"] +FilterByTime --> ExtractData["抽取源表数据"] +ExtractData --> ExtractTargetData["抽取目标表数据"] +ExtractTargetData --> CompareValues["比较数值"] +CompareValues --> CalculateDiff["计算差异"] +CalculateDiff --> CheckThreshold["检查是否超出阈值"] +CheckThreshold --> End([结束]) +style FilterByTime fill:#f9f,stroke:#333,stroke-width:2px +``` + +**图源** +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L87-L92) +- [CommonConstants.java](file://datavines-common\src\main\java\io\datavines\common\CommonConstants.java#L277-L282) + +### 大规模数据的增量比对 + +对于大规模数据的比对,建议采用增量比对策略,只比对最近一段时间内发生变化的数据,而不是全量比对。可以通过在查询SQL中添加增量条件来实现。 + +```sql +-- 源表增量查询 +SELECT SUM(amount) as actual_value +FROM sales_fact +WHERE update_time >= '${last_check_time}' + AND date = '${system.biz.date}' + +-- 目标表增量查询 +SELECT SUM(amount) as expected_value +FROM sales_fact_dw +WHERE update_time >= '${last_check_time}' + AND date = '${system.biz.date}' +``` + +**章节源** +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java#L61-L62) +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L87-L92) + +## 常见问题与解决方案 + +### 单位不一致问题 + +当源系统和目标系统的数值单位不一致时(如源系统为元,目标系统为分),需要在查询SQL中进行单位转换。 + +**解决方案**: +```sql +-- 源表查询(元转换为分) +SELECT SUM(amount * 100) as actual_value FROM sales_fact WHERE date = '${system.biz.date}' + +-- 目标表查询(保持为分) +SELECT SUM(amount) as expected_value FROM sales_fact_dw WHERE date = '${system.biz.date}' +``` + +### 汇率换算问题 + +当涉及跨国业务时,不同系统的货币单位可能不同,需要考虑汇率换算。 + +**解决方案**: +```sql +-- 使用汇率表进行换算 +SELECT SUM(s.amount * r.rate) as actual_value +FROM sales_fact s +JOIN exchange_rate r ON s.currency = r.from_currency AND r.to_currency = 'CNY' AND r.date = '${system.biz.date}' +WHERE s.date = '${system.biz.date}' +``` + +### 四舍五入误差 + +由于不同系统可能采用不同的四舍五入规则,可能导致微小的数值差异。 + +**解决方案**: +1. 设置合理的容差阈值(如0.01) +2. 在比较前统一四舍五入规则 +```sql +-- 统一保留两位小数 +SELECT ROUND(SUM(amount), 2) as actual_value FROM sales_fact WHERE date = '${system.biz.date}' +``` + +**章节源** +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java#L52-L53) +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L64-L68) + +## 结论 + +两表值比较检查是DataVines数据质量框架中一个强大而灵活的功能,能够有效验证不同表之间关键数值的一致性。通过合理的配置和使用,可以确保数据在ETL过程、系统迁移和业务运营中的准确性。该功能支持多种执行引擎(Local、Flink、Spark),并提供了丰富的配置选项和性能优化策略,能够满足不同规模和复杂度的数据质量检查需求。在实际应用中,应注意处理单位不一致、汇率换算和四舍五入误差等常见问题,以确保检查结果的准确性和可靠性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245/\350\267\250\350\241\250\345\207\206\347\241\256\346\200\247\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245/\350\267\250\350\241\250\345\207\206\347\241\256\346\200\247\346\243\200\346\237\245.md" new file mode 100644 index 00000000..a773f55c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245/\350\267\250\350\241\250\345\207\206\347\241\256\346\200\247\346\243\200\346\237\245.md" @@ -0,0 +1,405 @@ +# 跨表准确性检查 + + +**本文档中引用的文件** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java) +- [LocalMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableAccuracyMetricBuilder.java) +- [FlinkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-config\src\main\java\io\datavines\engine\flink\config\FlinkMultiTableAccuracyMetricBuilder.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) +- [MappingColumn.java](file://datavines-common\src\main\java\io\datavines\common\entity\MappingColumn.java) +- [submit_job_mysql_storage.json](file://datavines-runner\src\main\resources\submit_job_mysql_storage.json) + + +## 目录 +1. [简介](#简介) +2. [核心实现机制](#核心实现机制) +3. [配置参数详解](#配置参数详解) +4. [使用场景与示例](#使用场景与示例) +5. [执行流程分析](#执行流程分析) +6. [性能优化策略](#性能优化策略) +7. [常见问题与解决方案](#常见问题与解决方案) +8. [总结](#总结) + +## 简介 + +跨表准确性检查(MultiTableAccuracy)是DataVines数据质量框架中的一个重要功能,用于验证两个数据表之间的数据一致性。该功能通过主键或唯一键关联源表和目标表,检查两个表之间的数据是否一致,从而确保数据在迁移、同步或复制过程中的准确性。 + +该功能适用于多种场景,包括数据迁移验证、主从数据库同步校验、ETL过程数据一致性检查等。通过精确的数据比对,可以帮助用户及时发现数据不一致问题,保障数据质量。 + +**Section sources** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L44-L47) + +## 核心实现机制 + +跨表准确性检查的核心实现基于SQL的JOIN操作,通过LEFT JOIN将源表和目标表进行关联,然后识别出在源表中存在但在目标表中不存在的记录。 + +### 数据比对原理 + +跨表准确性检查的实现原理主要依赖于三个核心SQL语句的构建: + +1. **源表查询语句**:`SELECT * FROM ${table}` +2. **目标表查询语句**:`SELECT * FROM ${table2}` +3. **差异项查询语句**:通过LEFT JOIN构建的复合查询 + +```mermaid +flowchart TD +A[源表数据] --> |LEFT JOIN| B[目标表数据] +B --> C{关联条件匹配} +C --> |是| D[一致性记录] +C --> |否| E[不一致记录] +E --> F[输出差异数据] +``` + +**Diagram sources** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L33-L37) + +### 关联字段配置 + +系统通过`MappingColumn`类来定义两个表之间的字段映射关系。每个`MappingColumn`对象包含三个属性: +- `column`:源表字段名 +- `operator`:比较操作符 +- `column2`:目标表字段名 + +这些映射关系用于构建JOIN条件和WHERE子句,确保两个表能够正确关联。 + +```mermaid +classDiagram +class MappingColumn { ++String column ++String operator ++String column2 +} +``` + +**Diagram sources** +- [MappingColumn.java](file://datavines-common\src\main\java\io\datavines\common\entity\MappingColumn.java#L29-L36) + +**Section sources** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L33-L94) +- [MappingColumn.java](file://datavines-common\src\main\java\io\datavines\common\entity\MappingColumn.java#L29-L36) + +## 配置参数详解 + +跨表准确性检查功能提供了丰富的配置参数,允许用户灵活定义数据比对的各个方面。 + +### 基础连接配置 + +| 参数 | 说明 | 必填 | +|------|------|------| +| `table` | 源表名称 | 是 | +| `table2` | 目标表名称 | 是 | +| `database` | 源表数据库 | 是 | +| `database2` | 目标表数据库 | 否 | +| `filter` | 源表过滤条件 | 否 | +| `filter2` | 目标表过滤条件 | 否 | + +### 字段映射配置 + +字段映射通过`MAPPING_COLUMNS`参数进行配置,采用JSON数组格式定义多个字段的映射关系: + +```json +[ + { + "column": "id", + "operator": "=", + "column2": "user_id" + }, + { + "column": "name", + "operator": "=", + "column2": "full_name" + } +] +``` + +### 别名配置 + +| 参数 | 说明 | +|------|------| +| `table_alias` | 源表别名 | +| `table2_alias` | 目标表别名 | +| `table_alias_columns` | 源表字段列表 | +| `table2_alias_columns` | 目标表字段列表 | + +### 关联条件配置 + +系统自动根据字段映射生成JOIN条件和WHERE子句: + +- `ON_CLAUSE`:基于字段映射生成的JOIN条件 +- `WHERE_CLAUSE`:用于识别不一致记录的过滤条件 + +**Section sources** +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java#L53-L57) +- [LocalMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableAccuracyMetricBuilder.java#L57-L61) + +## 使用场景与示例 + +### 数据迁移验证 + +在数据从旧系统迁移到新系统后,使用跨表准确性检查验证数据完整性: + +```json +{ + "metricParameterList": [ + { + "metricType": "multi_table_accuracy", + "metricParameter": { + "table": "users_old", + "table2": "users_new", + "database": "legacy_db", + "database2": "modern_db", + "mapping_columns": "[{\"column\":\"id\",\"operator\":\"=\",\"column2\":\"user_id\"},{\"column\":\"email\",\"operator\":\"=\",\"column2\":\"email\"}]", + "table_alias": "t1", + "table2_alias": "t2" + } + } + ] +} +``` + +### 主从数据库同步校验 + +定期检查主数据库和从数据库之间的数据一致性: + +```json +{ + "metricParameterList": [ + { + "metricType": "multi_table_accuracy", + "metricParameter": { + "table": "orders", + "table2": "orders", + "database": "master_db", + "database2": "slave_db", + "filter": "created_date > '2023-01-01'", + "filter2": "created_date > '2023-01-01'", + "mapping_columns": "[{\"column\":\"order_id\",\"operator\":\"=\",\"column2\":\"order_id\"},{\"column\":\"amount\",\"operator\":\"=\",\"column2\":\"amount\"}]" + } + } + ] +} +``` + +### ETL过程数据一致性检查 + +在ETL流程完成后,验证源数据和目标数据仓库之间的一致性: + +```json +{ + "metricParameterList": [ + { + "metricType": "multi_table_accuracy", + "metricParameter": { + "table": "raw_sales", + "table2": "dw_sales_fact", + "database": "staging", + "database2": "data_warehouse", + "mapping_columns": "[{\"column\":\"transaction_id\",\"operator\":\"=\",\"column2\":\"fact_id\"},{\"column\":\"amount\",\"operator\":\"=\",\"column2\":\"sales_amount\"},{\"column\":\"customer_id\",\"operator\":\"=\",\"column2\":\"customer_dim_id\"}]", + "table_alias": "src", + "table2_alias": "tgt" + } + } + ] +} +``` + +**Section sources** +- [submit_job_mysql_storage.json](file://datavines-runner\src\main\resources\submit_job_mysql_storage.json#L17-L32) + +## 执行流程分析 + +跨表准确性检查的执行流程分为多个阶段,每个阶段都有明确的职责。 + +### 配置准备阶段 + +在`prepare`方法中,系统根据配置参数构建SQL查询语句: + +```mermaid +sequenceDiagram +participant Config as 配置参数 +participant Builder as MetricBuilder +participant SQL as SQL生成器 +Config->>Builder : 提交配置参数 +Builder->>SQL : 构建源表查询 +Builder->>SQL : 构建目标表查询 +Builder->>SQL : 构建差异查询 +SQL-->>Builder : 返回完整SQL +Builder-->>Config : 完成配置准备 +``` + +**Diagram sources** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L80-L94) + +### 数据抽取阶段 + +系统执行构建好的SQL语句,从源表和目标表抽取数据: + +```mermaid +flowchart TD +A[开始执行] --> B{检查过滤条件} +B --> |存在| C[添加WHERE子句] +B --> |不存在| D[直接查询全表] +C --> E[执行源表查询] +D --> E +E --> F[执行目标表查询] +F --> G[执行JOIN操作] +G --> H[识别差异数据] +H --> I[输出结果] +``` + +**Diagram sources** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L102-L109) + +### 结果计算阶段 + +系统通过以下步骤计算最终结果: + +1. 执行`getInvalidateItems`获取不一致的记录 +2. 执行`getActualValue`统计不一致记录的数量 +3. 执行`getDirectActualValue`直接获取统计结果 + +```mermaid +graph TD +A[获取差异项] --> B[统计数量] +B --> C[生成结果] +C --> D[存储结果] +D --> E[返回结果] +``` + +**Diagram sources** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L102-L129) + +**Section sources** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L80-L129) + +## 性能优化策略 + +### 分区字段利用 + +对于大表数据比对,建议使用分区字段来减少数据扫描量: + +```json +{ + "filter": "partition_date = '2023-01-01'", + "filter2": "partition_date = '2023-01-01'" +} +``` + +通过在`filter`和`filter2`参数中指定分区条件,可以显著减少需要比对的数据量,提高执行效率。 + +### 大表JOIN优化 + +对于大表JOIN操作,系统提供了以下优化策略: + +1. **索引利用**:确保关联字段上有适当的索引 +2. **数据预过滤**:通过`filter`参数提前过滤数据 +3. **分批处理**:对于超大表,考虑分批进行数据比对 + +### 执行引擎优化 + +不同执行引擎的优化配置: + +#### Spark引擎优化 +```java +// Spark引擎配置优化 +SparkMultiTableAccuracyMetricBuilder builder = new SparkMultiTableAccuracyMetricBuilder(); +// 启用广播JOIN优化小表 +builder.setBroadcastJoinThreshold(10485760); // 10MB +``` + +#### Flink引擎优化 +```java +// Flink引擎配置优化 +FlinkMultiTableAccuracyMetricBuilder builder = new FlinkMultiTableAccuracyMetricBuilder(); +// 配置状态后端和检查点 +builder.setStateBackend("rocksdb"); +builder.setCheckpointInterval(60000); +``` + +#### Local引擎优化 +```java +// Local引擎配置优化 +LocalMultiTableAccuracyMetricBuilder builder = new LocalMultiTableAccuracyMetricBuilder(); +// 配置内存限制 +builder.setMaxMemory("2g"); +// 启用并行处理 +builder.setParallelism(4); +``` + +**Section sources** +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java#L44-L63) +- [FlinkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-config\src\main\java\io\datavines\engine\flink\config\FlinkMultiTableAccuracyMetricBuilder.java#L42-L61) +- [LocalMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableAccuracyMetricBuilder.java#L48-L67) + +## 常见问题与解决方案 + +### 数据类型不匹配 + +**问题描述**:源表和目标表的关联字段数据类型不一致,导致JOIN失败。 + +**解决方案**: +1. 在数据库中统一字段数据类型 +2. 使用CAST函数进行类型转换 +3. 在配置中添加类型转换规则 + +```json +{ + "mapping_columns": "[{\"column\":\"id\",\"operator\":\"=\",\"column2\":\"CAST(user_id AS VARCHAR)\"}]" +} +``` + +### 空值处理 + +**问题描述**:NULL值在JOIN操作中不匹配,导致误报不一致记录。 + +**解决方案**: +1. 使用COALESCE函数处理NULL值 +2. 在WHERE子句中明确处理NULL情况 +3. 配置空值替换规则 + +```java +// 在MetricParserUtils中处理空值 +public static String getCoalesceString(String table, String column, boolean needQuote) { + return String.format("COALESCE(CAST(%s.%s AS STRING), '')", table, QuoteIdentifier.quote(column, needQuote)); +} +``` + +### 字符编码差异 + +**问题描述**:不同数据库系统的字符编码不一致,导致字符串比较失败。 + +**解决方案**: +1. 统一数据库字符编码为UTF-8 +2. 在比较前进行字符编码转换 +3. 使用二进制比较模式 + +```sql +-- 使用BINARY关键字进行二进制比较 +ON BINARY t1.name = BINARY t2.full_name +``` + +### 性能瓶颈 + +**问题描述**:大表JOIN操作执行缓慢,消耗大量资源。 + +**解决方案**: +1. 添加适当的索引 +2. 使用分区过滤减少数据量 +3. 调整执行引擎资源配置 +4. 考虑分批处理策略 + +**Section sources** +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java#L193-L195) +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L81-L87) + +## 总结 + +跨表准确性检查是DataVines数据质量框架中的核心功能之一,通过精确的SQL操作实现了两个数据表之间的数据一致性验证。该功能具有以下特点: + +1. **灵活性**:支持多种数据库类型和复杂的字段映射关系 +2. **可配置性**:提供丰富的配置参数,满足不同场景需求 +3. **高效性**:通过优化的SQL生成和执行策略,确保大表比对的性能 +4. **易用性**:统一的API接口和清晰的执行流程,便于集成和使用 + +通过合理配置和优化,跨表准确性检查可以有效保障数据在各种场景下的质量和一致性,是数据治理和数据质量管理的重要工具。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245/\350\267\250\350\241\250\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245/\350\267\250\350\241\250\346\243\200\346\237\245.md" new file mode 100644 index 00000000..7f742857 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245/\350\267\250\350\241\250\346\243\200\346\237\245.md" @@ -0,0 +1,300 @@ +# 跨表检查 + + +**本文档引用的文件** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java) +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [SparkSinkSqlBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSinkSqlBuilder.java) + + +## 目录 +1. [引言](#引言) +2. [跨表准确性检查](#跨表准确性检查) +3. [两表值比对检查](#两表值比对检查) +4. [配置参数详解](#配置参数详解) +5. [应用场景](#应用场景) +6. [性能优化策略](#性能优化策略) +7. [总结](#总结) + +## 引言 + +DataVines 是一个数据质量验证平台,支持多种数据质量检查规则,其中跨表检查是确保数据一致性和准确性的关键机制。跨表检查主要包括跨表准确性检查(MultiTableAccuracy)和两表值比对检查(MultiTableValueComparison)。这些规则通过比较不同表中的数据,验证数据同步、迁移和主从数据库之间的一致性。本文档详细描述了这两种跨表检查规则的实现原理、配置方法和应用场景,并提供性能优化建议。 + +## 跨表准确性检查 + +跨表准确性检查(MultiTableAccuracy)用于验证源表和目标表之间的数据一致性。该规则通过主键关联两个表,检查源表中的记录是否在目标表中存在,从而确保数据的完整性和准确性。 + +### 实现原理 + +跨表准确性检查的核心是通过 SQL 的 LEFT JOIN 操作来比较两个表的数据。具体实现如下: + +1. **构建源表和目标表的查询语句**:使用 `SELECT * FROM ${table}` 和 `SELECT * FROM ${table2}` 分别构建源表和目标表的查询语句。 +2. **添加过滤条件**:如果配置了过滤条件(filter),则在查询语句中添加 `WHERE` 子句。 +3. **构建无效项查询语句**:通过 LEFT JOIN 将源表和目标表连接起来,生成一个包含所有源表记录和匹配的目标表记录的结果集。然后使用 `WHERE` 子句筛选出源表中存在但目标表中不存在的记录。 +4. **计算不一致记录数**:使用 `COUNT(1)` 函数计算不一致记录的数量。 + +```java +public class MultiTableAccuracy implements SqlMetric { + private final StringBuilder sourceTableSql = new StringBuilder("SELECT * FROM ${table}"); + private final StringBuilder targetTableSql = new StringBuilder("SELECT * FROM ${table2}"); + private final StringBuilder invalidateItemsSql = new StringBuilder("SELECT ${table_alias_columns}, ${table2_alias_columns} FROM "); + + @Override + public void prepare(Map config) { + if (config.containsKey("filter") && StringUtils.isNotBlank(config.get("filter"))) { + sourceTableSql.append(" WHERE (${filter}) "); + } + + if (config.containsKey("filter2") && StringUtils.isNotBlank(config.get("filter2"))) { + targetTableSql.append(" WHERE (${filter2}) "); + } + + invalidateItemsSql + .append("(").append(sourceTableSql).append(")").append(" ${table_alias} ") + .append(" LEFT JOIN ") + .append("(").append(targetTableSql).append(")").append(" ${table2_alias} ") + .append("ON ${on_clause} WHERE ${where_clause}"); + } + + @Override + public ExecuteSql getInvalidateItems(Map inputParameter) { + String uniqueKey = inputParameter.get(METRIC_UNIQUE_KEY); + ExecuteSql executeSql = new ExecuteSql(); + executeSql.setResultTable("invalidate_items_" + uniqueKey); + executeSql.setSql(invalidateItemsSql.toString()); + executeSql.setErrorOutput(isInvalidateItemsCanOutput()); + return executeSql; + } + + @Override + public ExecuteSql getActualValue(Map inputParameter) { + String uniqueKey = inputParameter.get(METRIC_UNIQUE_KEY); + ExecuteSql executeSql = new ExecuteSql(); + executeSql.setResultTable("invalidate_count_" + uniqueKey); + executeSql.setSql("select count(1) as actual_value_" + uniqueKey + " from ${invalidate_items_table}"); + executeSql.setErrorOutput(false); + return executeSql; + } +} +``` + +### 配置示例 + +```json +{ + "metricType": "multi_table_accuracy", + "metricParameter": { + "table": "source_table", + "table2": "target_table", + "database": "source_db", + "database2": "target_db", + "mappingColumns": [ + { + "column": "id", + "column2": "id", + "operator": "=" + } + ], + "filter": "status = 'active'", + "filter2": "status = 'active'" + }, + "expectedType": "fix_value", + "expectedParameter": { + "expected_value": "0" + }, + "resultFormula": "count", + "operator": "eq", + "threshold": 0.0 +} +``` + +**Section sources** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L32-L136) + +## 两表值比对检查 + +两表值比对检查(MultiTableValueComparison)用于验证不同表中相同业务含义字段的数值一致性。该规则通过比较两个表中指定字段的值,确保数据在不同系统或环境中的准确性。 + +### 实现原理 + +两表值比对检查的核心是通过 SQL 的 JOIN 操作来比较两个表中指定字段的值。具体实现如下: + +1. **构建源表和目标表的查询语句**:使用 `SELECT * FROM ${table}` 和 `SELECT * FROM ${table2}` 分别构建源表和目标表的查询语句。 +2. **添加过滤条件**:如果配置了过滤条件(filter),则在查询语句中添加 `WHERE` 子句。 +3. **构建比较字段的查询语句**:通过 JOIN 将源表和目标表连接起来,生成一个包含所有源表记录和匹配的目标表记录的结果集。然后使用 `WHERE` 子句筛选出指定字段值不一致的记录。 +4. **计算不一致记录数**:使用 `COUNT(1)` 函数计算不一致记录的数量。 + +```java +public class MultiTableValueComparison implements SqlMetric { + @Override + public String getName() { + return "multi_table_value_comparison"; + } + + @Override + public String getZhName() { + return "两表值比对"; + } + + @Override + public MetricDimension getDimension() { + return MetricDimension.ACCURACY; + } + + @Override + public MetricType getType() { + return MetricType.MULTI_TABLE_VALUE_COMPARISON; + } + + @Override + public boolean isInvalidateItemsCanOutput() { + return false; + } + + @Override + public ExecuteSql getInvalidateItems(Map inputParameter) { + return null; + } + + @Override + public ExecuteSql getActualValue(Map inputParameter) { + return null; + } + + @Override + public CheckResult validateConfig(Map config) { + return null; + } + + @Override + public Map getConfigMap() { + return null; + } + + @Override + public void prepare(Map config) { + } + + @Override + public List suitableType() { + return Collections.emptyList(); + } +} +``` + +### 配置示例 + +```json +{ + "metricType": "multi_table_value_comparison", + "metricParameter": { + "table": "source_table", + "table2": "target_table", + "database": "source_db", + "database2": "target_db", + "mappingColumns": [ + { + "column": "amount", + "column2": "amount", + "operator": "=" + } + ], + "filter": "status = 'active'", + "filter2": "status = 'active'" + }, + "expectedType": "fix_value", + "expectedParameter": { + "expected_value": "0" + }, + "resultFormula": "count", + "operator": "eq", + "threshold": 0.0 +} +``` + +**Section sources** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java#L31-L87) + +## 配置参数详解 + +### 关联字段设置 + +关联字段(mappingColumns)用于指定源表和目标表之间的关联关系。每个关联字段包含以下属性: + +- **column**:源表中的字段名。 +- **column2**:目标表中的字段名。 +- **operator**:比较操作符,如 `=`、`!=`、`>`、`<` 等。 + +### 比较字段选择 + +比较字段(column 和 column2)用于指定需要比较的字段。这些字段通常具有相同的业务含义,但在不同的表中可能有不同的名称。 + +### 容差阈值配置 + +容差阈值(threshold)用于定义允许的误差范围。例如,如果配置了 `threshold: 0.0`,则表示不允许有任何不一致的记录。 + +### 过滤条件 + +过滤条件(filter 和 filter2)用于在查询时添加额外的筛选条件。这些条件可以帮助减少数据扫描量,提高查询性能。 + +### 其他配置参数 + +- **METRIC_UNIQUE_KEY**:唯一键,用于标识每个度量任务。 +- **TABLE_ALIAS** 和 **TABLE2_ALIAS**:表别名,用于在 SQL 查询中引用表。 +- **ON_CLAUSE**:JOIN 条件,用于指定关联字段的比较条件。 +- **WHERE_CLAUSE**:WHERE 条件,用于指定过滤条件。 + +**Section sources** +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java#L19-L182) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java#L43-L223) + +## 应用场景 + +### 数据同步验证 + +在数据同步过程中,跨表准确性检查可以用于验证源系统和目标系统之间的数据一致性。例如,在 ETL 过程中,可以使用跨表准确性检查来确保源表中的所有记录都已正确同步到目标表中。 + +### 数据迁移校验 + +在数据迁移过程中,两表值比对检查可以用于验证迁移前后数据的准确性。例如,在将数据从旧系统迁移到新系统时,可以使用两表值比对检查来确保关键字段的值在迁移前后保持一致。 + +### 主从数据库一致性检查 + +在主从数据库架构中,跨表准确性检查可以用于验证主库和从库之间的数据一致性。例如,可以定期运行跨表准确性检查来确保从库中的数据与主库中的数据完全一致。 + +**Section sources** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L32-L136) +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java#L31-L87) + +## 性能优化策略 + +### 分区剪裁 + +通过在查询中添加分区过滤条件,可以显著减少数据扫描量。例如,如果数据按日期分区,可以在查询中添加 `WHERE date = '2023-10-01'` 来只扫描特定日期的数据。 + +### 优化 JOIN 操作 + +- **选择合适的 JOIN 类型**:根据数据特点选择合适的 JOIN 类型,如 INNER JOIN、LEFT JOIN 或 RIGHT JOIN。 +- **使用索引**:确保关联字段上有适当的索引,以加快 JOIN 操作的速度。 +- **减少 JOIN 的表数量**:尽量减少 JOIN 的表数量,避免复杂的多表 JOIN 操作。 + +### 缓存中间结果 + +对于频繁执行的查询,可以考虑缓存中间结果,以减少重复计算。例如,可以将 JOIN 操作的结果缓存到临时表中,后续查询可以直接使用缓存结果。 + +### 并行处理 + +利用分布式计算框架(如 Spark)的并行处理能力,可以显著提高大规模数据集的处理速度。通过将数据分片并在多个节点上并行处理,可以大幅缩短查询时间。 + +**Section sources** +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java#L42-L107) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java#L31-L75) +- [SparkSinkSqlBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSinkSqlBuilder.java#L26-L90) + +## 总结 + +跨表检查是 DataVines 平台中重要的数据质量验证机制,包括跨表准确性检查和两表值比对检查。这些规则通过 SQL 的 JOIN 操作来比较不同表中的数据,确保数据在不同系统或环境中的准确性和一致性。通过合理配置关联字段、比较字段和容差阈值,可以有效验证数据同步、迁移和主从数据库之间的一致性。此外,通过分区剪裁、优化 JOIN 操作、缓存中间结果和并行处理等性能优化策略,可以显著提高跨表检查的效率和性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\347\273\223\346\236\234\345\205\254\345\274\217.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\347\273\223\346\236\234\345\205\254\345\274\217.md" new file mode 100644 index 00000000..a70d6c76 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\347\273\223\346\236\234\345\205\254\345\274\217.md" @@ -0,0 +1,321 @@ +# 结果公式 + + +**本文档中引用的文件** +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [ResultFormulaType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormulaType.java) +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java) +- [Count.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-count/src/main/java/io/datavines/metric/result/formula/Count.java) +- [Diff.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff/src/main/java/io/datavines/metric/result/formula/Diff.java) +- [ActualMinusExpectedDiff.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-actual-expected/src/main/java/io/datavines/metric/result/formula/ActualMinusExpectedDiff.java) +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [MetricController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/MetricController.java) + + +## 目录 +1. [引言](#引言) +2. [结果公式类型](#结果公式类型) +3. [质量等级映射](#质量等级映射) +4. [结果公式扩展机制](#结果公式扩展机制) +5. [精度控制与性能优化](#精度控制与性能优化) +6. [异常处理与边界情况](#异常处理与边界情况) +7. [实际应用示例](#实际应用示例) +8. [结论](#结论) + +## 引言 + +结果公式是数据质量平台的核心组件,用于计算质量得分和评估数据质量。该系统通过定义不同的公式类型来满足各种质量检查需求,包括百分比、差异值、差异百分比和计数等。结果公式不仅计算实际值与期望值之间的关系,还根据业务需求生成相应的质量评分。本文档详细描述了结果公式的计算方法、类型分类、扩展机制以及与其他系统组件的集成方式。 + +**本节来源** +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) + +## 结果公式类型 + +### 计数公式 (Count) + +计数公式是最简单的结果公式类型,直接返回实际值作为计算结果。这种公式适用于只需要记录实际数值的场景,如记录表行数、空值数量等。其业务意义在于提供原始数据的直接度量,不进行任何转换或比较。 + +```mermaid +classDiagram +class Count { ++String getName() ++String getZhName() ++BigDecimal getResult(BigDecimal actualValue, BigDecimal expectedValue) ++BigDecimal getScore(BigDecimal actualValue, BigDecimal expectedValue, boolean isSuccess, MetricDirectionType direction) ++String getResultFormat(boolean isEn) ++String getSymbol() ++ResultFormulaType getType() +} +``` + +**图示来源** +- [Count.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-count/src/main/java/io/datavines/metric/result/formula/Count.java) + +### 绝对差异公式 (Diff) + +绝对差异公式计算实际值与期望值之间的绝对差值,即 |实际值 - 期望值|。这种公式适用于需要衡量偏差大小的场景,而不关心偏差的方向。其数学原理基于绝对值运算,确保结果始终为非负数。 + +```mermaid +classDiagram +class Diff { ++String getName() ++String getZhName() ++BigDecimal getResult(BigDecimal actualValue, BigDecimal expectedValue) ++BigDecimal getScore(BigDecimal actualValue, BigDecimal expectedValue, boolean isSuccess, MetricDirectionType direction) ++String getResultFormat(boolean isEn) ++String getSymbol() ++ResultFormulaType getType() +} +``` + +**图示来源** +- [Diff.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff/src/main/java/io/datavines/metric/result/formula/Diff.java) + +### 实际值减期望值公式 (ActualMinusExpectedDiff) + +实际值减期望值公式计算实际值与期望值之间的代数差值,即 实际值 - 期望值。与绝对差异公式不同,此公式保留了差异的符号信息,可以区分正向偏差和负向偏差。这在需要了解偏差方向的业务场景中非常有用。 + +```mermaid +classDiagram +class ActualMinusExpectedDiff { ++String getName() ++String getZhName() ++BigDecimal getResult(BigDecimal actualValue, BigDecimal expectedValue) ++BigDecimal getScore(BigDecimal actualValue, BigDecimal expectedValue, boolean isSuccess, MetricDirectionType direction) ++String getResultFormat(boolean isEn) ++String getSymbol() ++ResultFormulaType getType() +} +``` + +**图示来源** +- [ActualMinusExpectedDiff.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-actual-expected/src/main/java/io/datavines/metric/result/formula/ActualMinusExpectedDiff.java) + +### 百分比公式 (Percentage) + +百分比公式计算实际值相对于期望值的百分比,即 (实际值 / 期望值) × 100%。这种公式适用于需要评估完成率、达成率等相对指标的场景。其业务意义在于提供一个标准化的度量,便于跨不同规模的数据集进行比较。 + +```mermaid +classDiagram +class Percentage { ++String getName() ++String getZhName() ++BigDecimal getResult(BigDecimal actualValue, BigDecimal expectedValue) ++BigDecimal getScore(BigDecimal actualValue, BigDecimal expectedValue, boolean isSuccess, MetricDirectionType direction) ++String getResultFormat(boolean isEn) ++String getSymbol() ++ResultFormulaType getType() +} +``` + +**图示来源** +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) + +### 差异百分比公式 (DiffPercentage) + +差异百分比公式计算实际值与期望值之间差异的相对百分比,即 |实际值 - 期望值| / 期望值 × 100%。这种公式适用于需要评估偏差程度的场景,特别是在期望值本身具有重要意义时。它提供了一个标准化的偏差度量,便于比较不同规模数据的质量。 + +```mermaid +classDiagram +class DiffPercentage { ++String getName() ++String getZhName() ++BigDecimal getResult(BigDecimal actualValue, BigDecimal expectedValue) ++BigDecimal getScore(BigDecimal actualValue, BigDecimal expectedValue, boolean isSuccess, MetricDirectionType direction) ++String getResultFormat(boolean isEn) ++String getSymbol() ++ResultFormulaType getType() +} +``` + +**图示来源** +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) + +## 质量等级映射 + +质量等级映射是将计算得到的质量得分转换为可读性更强的质量等级的过程。系统定义了五个质量等级:优秀、良好、中等、合格和不合格。这些等级基于得分区间进行划分,为用户提供直观的质量评估。 + +```mermaid +flowchart TD +Start([开始]) --> CheckScore["检查质量得分"] +CheckScore --> Excellent{"得分 >= 80?"} +Excellent --> |是| Good{"得分 >= 80?"} +Excellent --> |否| Medium{"得分 >= 60?"} +Good --> |是| ExcellentLevel["质量等级: 优秀"] +Medium --> |是| GoodLevel["质量等级: 良好"] +Medium --> |否| Qualified{"得分 >= 40?"} +Qualified --> |是| MediumLevel["质量等级: 中等"] +Qualified --> |否| UnqualifiedLevel["质量等级: 不合格"] +ExcellentLevel --> End([结束]) +GoodLevel --> End +MediumLevel --> End +UnqualifiedLevel --> End +``` + +**图示来源** +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java) + +## 结果公式扩展机制 + +### 插件化架构 + +结果公式系统采用插件化架构设计,通过 SPI (Service Provider Interface) 机制实现扩展。每个结果公式实现都作为一个独立的插件存在,系统在运行时动态加载和管理这些插件。这种设计提供了高度的灵活性和可扩展性。 + +```mermaid +graph TD +subgraph "核心模块" +ResultFormulaInterface[ResultFormula接口] +PluginLoader[插件加载器] +end +subgraph "插件模块" +CountPlugin[计数公式插件] +DiffPlugin[差异公式插件] +PercentagePlugin[百分比公式插件] +DiffPercentagePlugin[差异百分比插件] +end +PluginLoader --> ResultFormulaInterface +CountPlugin --> ResultFormulaInterface +DiffPlugin --> ResultFormulaInterface +PercentagePlugin --> ResultFormulaInterface +DiffPercentagePlugin --> ResultFormulaInterface +``` + +**图示来源** +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [MetricController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/MetricController.java) + +### 自定义公式开发 + +开发自定义结果公式需要遵循以下步骤:首先实现 `ResultFormula` 接口,然后在 `META-INF/plugins` 目录下创建服务配置文件,最后将插件打包并部署到系统中。这种机制允许用户根据特定业务需求开发和集成新的计算公式。 + +```mermaid +sequenceDiagram +participant Developer as "开发者" +participant IDE as "开发环境" +participant BuildSystem as "构建系统" +participant Deployment as "部署环境" +Developer->>IDE : 实现ResultFormula接口 +IDE->>IDE : 编写公式逻辑 +Developer->>BuildSystem : 构建插件包 +BuildSystem->>BuildSystem : 打包JAR文件 +BuildSystem->>Deployment : 部署插件 +Deployment->>Deployment : 加载新公式 +Deployment-->>Developer : 可用的新公式 +``` + +**图示来源** +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) + +## 精度控制与性能优化 + +### 精度控制 + +系统在计算过程中采用 `BigDecimal` 类型进行高精度计算,避免浮点数运算带来的精度损失。对于除法运算,系统指定了明确的舍入模式(如 HALF_UP)和小数位数(通常为4位),确保计算结果的一致性和可预测性。 + +```mermaid +flowchart TD +Input["输入: 实际值, 期望值"] --> CheckNull["检查空值"] +CheckNull --> |非空| CheckZero["检查期望值是否为零"] +CheckZero --> |非零| Division["执行除法运算"] +Division --> Rounding["应用舍入规则"] +Rounding --> Output["输出: 高精度结果"] +CheckNull --> |空值| ReturnZero["返回零值"] +CheckZero --> |为零| ReturnZero +ReturnZero --> Output +``` + +**图示来源** +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) + +### 性能优化 + +系统通过缓存机制优化性能,避免重复加载和实例化相同的公式插件。`PluginLoader` 负责管理插件的生命周期,确保每个插件在系统中只有一个实例,从而减少内存占用和初始化开销。 + +```mermaid +classDiagram +class PluginLoader { +-Map pluginCache ++getPluginLoader(Class clazz) PluginLoader ++getSupportedPlugins() Set ++getOrCreatePlugin(String pluginName) T +} +class ResultFormula { +<> +} +PluginLoader "1" --> "0..*" ResultFormula : 缓存 +``` + +**图示来源** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) + +## 异常处理与边界情况 + +### 异常处理机制 + +系统在计算过程中充分考虑了各种异常情况,如空值、除零错误等。当遇到这些情况时,系统会返回安全的默认值(通常是零值),而不是抛出异常,确保整个质量检查流程的稳定性。 + +```mermaid +flowchart TD +Start["开始计算"] --> CheckActual["检查实际值"] +CheckActual --> |空值| HandleNull["处理空值"] +CheckActual --> |非空| CheckExpected["检查期望值"] +CheckExpected --> |空值| HandleNull +CheckExpected --> |非空| CheckDivision["检查是否为除法运算"] +CheckDivision --> |是| CheckZero["检查除数是否为零"] +CheckZero --> |为零| HandleZero["处理除零"] +CheckZero --> |非零| Calculate["正常计算"] +HandleNull --> ReturnZero["返回零值"] +HandleZero --> ReturnZero +Calculate --> ReturnResult["返回计算结果"] +ReturnZero --> End["结束"] +ReturnResult --> End +``` + +**图示来源** +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) + +### 边界情况处理 + +系统特别处理了多种边界情况,包括:当期望值为零时的除法运算、实际值或期望值为空的情况、以及极端大数值的计算。这些处理确保了系统在各种输入条件下都能稳定运行。 + +**本节来源** +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) + +## 实际应用示例 + +### 表行数质量检查 + +在表行数质量检查中,使用计数公式直接返回实际行数。如果实际行数达到预期目标,则质量得分为100分,否则为0分。这种检查适用于监控数据表的完整性。 + +**本节来源** +- [Count.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-count/src/main/java/io/datavines/metric/result/formula/Count.java) + +### 数据新鲜度检查 + +在数据新鲜度检查中,使用差异公式计算实际更新时间与期望更新时间之间的差异。较小的差异值表示数据更新及时,质量较高。这种检查适用于监控数据的时效性。 + +**本节来源** +- [Diff.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff/src/main/java/io/datavines/metric/result/formula/Diff.java) + +### 完成率检查 + +在完成率检查中,使用百分比公式计算实际完成量与预期目标的比率。例如,在数据同步任务中,计算已同步记录数占总记录数的比例。这种检查提供了直观的进度评估。 + +**本节来源** +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) + +### 偏差程度检查 + +在偏差程度检查中,使用差异百分比公式评估实际值与期望值之间的相对偏差。例如,在财务数据核对中,计算两个系统间金额差异的百分比。这种检查有助于识别潜在的数据质量问题。 + +**本节来源** +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) + +## 结论 + +结果公式系统为数据质量平台提供了灵活而强大的计算能力。通过定义多种公式类型,系统能够满足各种质量检查需求。插件化架构设计使得系统具有良好的可扩展性,允许用户根据业务需求开发自定义公式。同时,系统在精度控制、性能优化和异常处理方面都进行了充分考虑,确保了计算的准确性和系统的稳定性。质量等级映射机制将复杂的数值计算结果转化为直观的等级评估,便于用户理解和决策。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\347\273\223\346\236\234\351\252\214\350\257\201.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\347\273\223\346\236\234\351\252\214\350\257\201.md" new file mode 100644 index 00000000..b10b5fc6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\347\273\223\346\236\234\351\252\214\350\257\201.md" @@ -0,0 +1,370 @@ +# 结果验证 + + +**本文档引用的文件** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java) +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) +- [DailyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [WeeklyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) + + +## 目录 +1. [引言](#引言) +2. [结果验证流程](#结果验证流程) +3. [结果验证器工作原理](#结果验证器工作原理) +4. [结果计算机制](#结果计算机制) +5. [预期值计算方式](#预期值计算方式) +6. [质量等级划分标准](#质量等级划分标准) +7. [异常处理机制](#异常处理机制) +8. [性能优化建议](#性能优化建议) +9. [扩展性设计](#扩展性设计) + +## 引言 +本文档详细描述了大数据质量检查系统中质量检查结果的验证、计算和评估机制。系统通过JobResultValidator组件对数据质量检查任务的执行结果进行验证,包括实际值提取、预期值计算和结果比较。文档将深入解析结果验证器的工作原理,说明如何配置结果公式来计算质量得分,以及如何通过多种方式计算预期值。同时,文档还将介绍质量等级的划分标准、告警阈值设置、异常处理机制和性能优化建议。 + +## 结果验证流程 + +```mermaid +flowchart TD +Start([开始验证]) --> GetResults["获取任务执行结果"] +GetResults --> CheckEmpty{"结果为空?"} +CheckEmpty --> |是| End([结束]) +CheckEmpty --> |否| ProcessResults["遍历每个检查结果"] +ProcessResults --> CheckExpected{"期望值为空且非固定值?"} +CheckExpected --> |是| SetActualAsExpected["将实际值设为期望值"] +SetActualAsExpected --> UpdateDB["更新数据库"] +CheckExpected --> |否| ValidateResult["验证检查结果"] +ValidateResult --> IsSuccess{"验证成功?"} +IsSuccess --> |否| SendAlert["发送告警"] +IsSuccess --> |是| Continue["继续处理"] +Continue --> MoreResults{"还有更多结果?"} +MoreResults --> |是| ProcessResults +MoreResults --> |否| End +``` + +**图示来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L73-L102) + +**本节来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L73-L102) + +## 结果验证器工作原理 + +结果验证器(JobResultValidator)是数据质量检查系统的核心组件,负责对质量检查任务的执行结果进行验证和评估。其工作流程主要包括以下几个步骤: + +1. **获取执行结果**:通过JobExternalService从数据库中获取指定任务执行ID的所有检查结果。 +2. **遍历检查结果**:对每个检查结果进行处理,确保所有质量检查项都得到验证。 +3. **期望值处理**:当期望值为空且不是固定值类型时,将实际值设置为期望值,确保后续比较的准确性。 +4. **结果验证**:调用checkDqExecuteResult方法对每个检查结果进行验证。 +5. **告警处理**:如果任何检查结果失败,触发告警机制发送通知。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Validator as "JobResultValidator" +participant Service as "JobExternalService" +participant DB as "数据库" +Client->>Validator : operateDqExecuteResult() +Validator->>Service : listJobExecutionResultByJobExecutionId() +Service->>DB : 查询执行结果 +DB-->>Service : 返回结果列表 +Service-->>Validator : 返回结果列表 +Validator->>Validator : 遍历每个结果 +loop 处理每个检查结果 +Validator->>Validator : checkDqExecuteResult() +alt 期望值为空且非固定值 +Validator->>Validator : 设置实际值为期望值 +Validator->>Service : updateById() +end +Validator->>Validator : 验证结果 +alt 验证失败 +Validator->>Validator : sendErrorEmail() +end +end +Validator-->>Client : 完成验证 +``` + +**图示来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L73-L124) + +**本节来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L73-L124) + +## 结果计算机制 + +结果计算机制是质量检查系统的核心,通过配置不同的结果公式来计算质量得分。系统支持多种计算方式,包括百分比、差异值和合格率等。 + +### 结果公式类型 + +```mermaid +classDiagram +class ResultFormula { ++getName() String ++getZhName() String ++getNameByLanguage(isEn) String ++getResult(actualValue, expectedValue) BigDecimal ++getScore(actualValue, expectedValue, isSuccess, direction) BigDecimal ++getResultFormat(isEn) String ++getSymbol() String ++getType() ResultFormulaType +} +class Percentage { ++getResult(actualValue, expectedValue) BigDecimal ++getScore(actualValue, expectedValue, isSuccess, direction) BigDecimal ++getResultFormat(isEn) String +} +class DiffPercentage { ++getResult(actualValue, expectedValue) BigDecimal ++getScore(actualValue, expectedValue, isSuccess, direction) BigDecimal ++getResultFormat(isEn) String +} +class Diff { ++getResult(actualValue, expectedValue) BigDecimal ++getScore(actualValue, expectedValue, isSuccess, direction) BigDecimal ++getResultFormat(isEn) String +} +class ActualMinusExpectedDiff { ++getResult(actualValue, expectedValue) BigDecimal ++getScore(actualValue, expectedValue, isSuccess, direction) BigDecimal ++getResultFormat(isEn) String +} +ResultFormula <|-- Percentage +ResultFormula <|-- DiffPercentage +ResultFormula <|-- Diff +ResultFormula <|-- ActualMinusExpectedDiff +``` + +**图示来源** +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) + +**本节来源** +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) + +### 结果计算流程 + +```mermaid +flowchart TD +Start([开始计算]) --> GetValues["获取实际值和期望值"] +GetValues --> GetFormula["获取结果公式"] +GetFormula --> CalculateResult["计算结果值"] +CalculateResult --> GetDirection["获取指标方向"] +GetDirection --> CalculateScore["计算质量得分"] +CalculateScore --> ReturnResult["返回最终得分"] +``` + +**图示来源** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java#L47-L57) + +**本节来源** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java#L47-L57) + +## 预期值计算方式 + +系统支持多种预期值计算方式,以适应不同的业务场景和数据特征。这些计算方式通过插件化设计实现,便于扩展和维护。 + +### 预期值计算类型 + +```mermaid +classDiagram +class ExpectedValue { ++getName() String ++getZhName() String ++getNameByLanguage(isEn) String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +class FixValue { ++getExecuteSql(inputParameter) String ++getKey(inputParameter) String +} +class DailyAvg { ++getExecuteSql(inputParameter) String ++getKey(inputParameter) String +} +class WeeklyAvg { ++getExecuteSql(inputParameter) String ++getKey(inputParameter) String +} +class MonthlyAvg { ++getExecuteSql(inputParameter) String ++getKey(inputParameter) String +} +class TargetTableTotalRows { ++getExecuteSql(inputParameter) String ++getKey(inputParameter) String +} +ExpectedValue <|-- FixValue +ExpectedValue <|-- DailyAvg +ExpectedValue <|-- WeeklyAvg +ExpectedValue <|-- MonthlyAvg +ExpectedValue <|-- TargetTableTotalRows +``` + +**图示来源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [DailyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [WeeklyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) + +**本节来源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [DailyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [WeeklyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) + +### 预期值计算流程 + +```mermaid +flowchart TD +Start([开始计算]) --> GetConfig["获取配置参数"] +GetConfig --> DetermineType["确定预期值类型"] +DetermineType --> ExecuteSql{"是否需要执行SQL?"} +ExecuteSql --> |是| BuildSql["构建SQL查询"] +BuildSql --> ExecuteQuery["执行查询获取预期值"] +ExecuteSql --> |否| UseFixed["使用固定值"] +UseFixed --> ReturnResult["返回预期值"] +ExecuteQuery --> ReturnResult +``` + +**本节来源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [DailyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) + +## 质量等级划分标准 + +系统根据质量得分将数据质量划分为不同的等级,便于用户快速了解数据质量状况。质量等级的划分标准基于得分区间,每个等级都有明确的定义。 + +### 质量等级定义 + +| 质量等级 | 得分区间 | 描述 | +|---------|--------|------| +| 优秀 | 80-100 | 数据质量非常高,完全满足业务要求 | +| 良好 | 60-80 | 数据质量较高,基本满足业务要求 | +| 中等 | 40-60 | 数据质量一般,需要关注和改进 | +| 合格 | 20-40 | 数据质量较低,存在较多问题 | +| 不合格 | 0-20 | 数据质量很差,严重影响业务 | + +### 质量等级判定流程 + +```mermaid +flowchart TD +Start([开始判定]) --> GetScore["获取质量得分"] +GetScore --> CheckExcellent{"得分>=80?"} +CheckExcellent --> |是| SetExcellent["等级: 优秀"] +CheckExcellent --> |否| CheckGood{"得分>=60?"} +CheckGood --> |是| SetGood["等级: 良好"] +CheckGood --> |否| CheckMedium{"得分>=40?"} +CheckMedium --> |是| SetMedium["等级: 中等"] +CheckMedium --> |否| CheckQualified{"得分>=20?"} +CheckQualified --> |是| SetQualified["等级: 合格"] +CheckQualified --> |否| SetUnqualified["等级: 不合格"] +SetExcellent --> End +SetGood --> End +SetMedium --> End +SetQualified --> End +SetUnqualified --> End +``` + +**图示来源** +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java#L57-L73) + +**本节来源** +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java#L57-L73) + +## 异常处理机制 + +系统设计了完善的异常处理机制,确保在各种异常情况下仍能正常运行并提供准确的反馈。 + +### 异常处理策略 + +系统支持多种异常处理策略,用户可以根据业务需求进行配置: + +- **重试策略**:当任务失败时,系统会按照配置的重试间隔进行重试,直到成功或达到最大重试次数。 +- **告警策略**:当任务失败时,系统仅发送告警通知,不影响后续任务的执行。 + +```mermaid +flowchart TD +Start([任务执行]) --> Success{"执行成功?"} +Success --> |是| NormalEnd["正常结束"] +Success --> |否| CheckStrategy{"检查失败策略"} +CheckStrategy --> Retry{"重试策略?"} +Retry --> |是| Wait["等待重试间隔"] +Wait --> RetryExecution["重新执行"] +RetryExecution --> Success +Retry --> |否| SendAlert["发送告警"] +SendAlert --> Continue["继续后续任务"] +NormalEnd --> End +Continue --> End +``` + +**本节来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L99-L101) +- [DqFailureStrategy.java](file://datavines-server/src/main/java/io/datavines/server/enums/DqFailureStrategy.java) + +## 性能优化建议 + +为了提高结果验证的性能,系统采用了多种优化策略,确保在大规模数据场景下仍能高效运行。 + +### 减少重复计算 + +系统通过以下方式减少重复计算: +- **缓存历史数据**:将历史计算结果缓存到数据库中,避免重复计算。 +- **批量处理**:对多个检查结果进行批量处理,减少数据库交互次数。 +- **预计算**:在数据写入时预先计算部分指标,减少验证时的计算量。 + +### 缓存策略 + +```mermaid +flowchart TD +Start([开始验证]) --> CheckCache{"缓存中存在?"} +CheckCache --> |是| UseCache["使用缓存结果"] +CheckCache --> |否| Calculate["计算结果"] +Calculate --> StoreCache["存储到缓存"] +StoreCache --> UseCache +UseCache --> ReturnResult["返回结果"] +``` + +**本节来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) + +## 扩展性设计 + +系统采用插件化设计,支持自定义验证逻辑的实现,具有良好的扩展性。 + +### 插件化架构 + +```mermaid +flowchart TD +PluginLoader["PluginLoader"] --> |加载| ExpectedValuePlugin["ExpectedValue插件"] +PluginLoader --> |加载| ResultFormulaPlugin["ResultFormula插件"] +PluginLoader --> |加载| MetricPlugin["SqlMetric插件"] +ExpectedValuePlugin --> FixValue["固定值"] +ExpectedValuePlugin --> DailyAvg["日均值"] +ExpectedValuePlugin --> WeeklyAvg["周均值"] +ExpectedValuePlugin --> MonthlyAvg["月均值"] +ExpectedValuePlugin --> Custom["自定义"] +ResultFormulaPlugin --> Percentage["百分比"] +ResultFormulaPlugin --> DiffPercentage["差异百分比"] +ResultFormulaPlugin --> Diff["差异值"] +ResultFormulaPlugin --> Custom["自定义"] +Custom --> |实现| SPIInterface["SPI接口"] +``` + +**本节来源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227.md" new file mode 100644 index 00000000..c2daa4c8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227.md" @@ -0,0 +1,426 @@ +# 预期值计算 + + +**本文档引用的文件** +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java) +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java) +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java) +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java) +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) +- [None.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-none\src\main\java\io\datavines\metric\expected\plugin\None.java) +- [TableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-table-rows\src\main\java\io\datavines\metric\expected\plugin\TableTotalRows.java) +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java) +- [MetricConstants.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\MetricConstants.java) +- [ExpectedValueExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-transform\src\main\java\io\datavines\engine\local\transform\sql\ExpectedValueExecutor.java) + + +## 目录 +1. [引言](#引言) +2. [预期值计算策略](#预期值计算策略) +3. [核心计算策略实现](#核心计算策略实现) +4. [性能优化机制](#性能优化机制) +5. [扩展接口说明](#扩展接口说明) +6. [容错与异常处理](#容错与异常处理) +7. [计算策略配置参数](#计算策略配置参数) +8. [结论](#结论) + +## 引言 + +预期值计算是数据质量平台中的核心功能之一,用于为数据质量指标提供基准参考值。本系统通过多种计算策略实现预期值的动态生成,包括固定值、历史平均值(日均、周均、月均、最近7天、最近30天等)和表行数等。这些策略通过插件化架构实现,支持灵活扩展和配置。系统利用SPI(Service Provider Interface)机制实现插件加载,确保了良好的可扩展性和维护性。 + +**Section sources** +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java#L1-L65) + +## 预期值计算策略 + +系统提供了多种预期值计算策略,每种策略针对不同的业务场景和数据特征。主要计算策略包括: + +- **固定值**:使用预设的固定数值作为预期值,适用于业务规则明确且稳定的场景 +- **历史平均值**:基于历史数据计算平均值,包括日均值、周均值、月均值、最近7天均值和最近30天均值 +- **表行数**:计算指定表的总行数作为预期值,适用于数据量监控场景 +- **无预期值**:不计算预期值,仅用于实际值的采集和监控 + +这些策略通过统一的接口`ExpectedValue`进行抽象,确保了计算逻辑的一致性和可扩展性。 + +```mermaid +classDiagram +class ExpectedValue { +<> ++getName() String ++getZhName() String ++getKey(Map~String,String~) String ++getExecuteSql(Map~String,String~) String ++getOutputTable(Map~String,String~) String ++isNeedDefaultDatasource() boolean ++prepare(Map~String,String~) void +} +class FixValue { ++getName() String ++getZhName() String ++getKey(Map~String,String~) String ++getExecuteSql(Map~String,String~) String ++getOutputTable(Map~String,String~) String ++isNeedDefaultDatasource() boolean ++prepare(Map~String,String~) void +} +class DailyAvg { ++getName() String ++getZhName() String ++getKey(Map~String,String~) String ++getExecuteSql(Map~String,String~) String ++getOutputTable(Map~String,String~) String ++isNeedDefaultDatasource() boolean ++prepare(Map~String,String~) void +} +class WeeklyAvg { ++getName() String ++getZhName() String ++getKey(Map~String,String~) String ++getExecuteSql(Map~String,String~) String ++getOutputTable(Map~String,String~) String ++isNeedDefaultDatasource() boolean ++prepare(Map~String,String~) void +} +class MonthlyAvg { ++getName() String ++getZhName() String ++getKey(Map~String,String~) String ++getExecuteSql(Map~String,String~) String ++getOutputTable(Map~String,String~) String ++isNeedDefaultDatasource() boolean ++prepare(Map~String,String~) void +} +class Last7DayAvg { ++getName() String ++getZhName() String ++getKey(Map~String,String~) String ++getExecuteSql(Map~String,String~) String ++getOutputTable(Map~String,String~) String ++isNeedDefaultDatasource() boolean ++prepare(Map~String,String~) void +} +class Last30DayAvg { ++getName() String ++getZhName() String ++getKey(Map~String,String~) String ++getExecuteSql(Map~String,String~) String ++getOutputTable(Map~String,String~) String ++isNeedDefaultDatasource() boolean ++prepare(Map~String,String~) void +} +class TableTotalRows { ++getName() String ++getZhName() String ++getKey(Map~String,String~) String ++getExecuteSql(Map~String,String~) String ++getOutputTable(Map~String,String~) String ++isNeedDefaultDatasource() boolean ++prepare(Map~String,String~) void +} +class None { ++getName() String ++getZhName() String ++getKey(Map~String,String~) String ++getExecuteSql(Map~String,String~) String ++getOutputTable(Map~String,String~) String ++isNeedDefaultDatasource() boolean ++prepare(Map~String,String~) void +} +ExpectedValue <|-- FixValue +ExpectedValue <|-- DailyAvg +ExpectedValue <|-- WeeklyAvg +ExpectedValue <|-- MonthlyAvg +ExpectedValue <|-- Last7DayAvg +ExpectedValue <|-- Last30DayAvg +ExpectedValue <|-- TableTotalRows +ExpectedValue <|-- None +``` + +**Diagram sources ** +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java#L1-L65) +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java#L1-L62) +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L1-L76) +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java#L1-L76) +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java#L1-L67) +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java#L1-L67) +- [SparkLast30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast30DayAvg.java#L1-L67) +- [TableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-table-rows\src\main\java\io\datavines\metric\expected\plugin\TableTotalRows.java#L1-L76) +- [None.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-none\src\main\java\io\datavines\metric\expected\plugin\None.java#L1-L63) + +## 核心计算策略实现 + +### 固定值计算策略 + +固定值计算策略通过`FixValue`类实现,该策略不依赖于任何历史数据或数据库查询,直接返回预设的固定值。这种策略适用于业务规则明确且不需要动态调整的场景。 + +```mermaid +flowchart TD +Start([开始]) --> CheckConfig["检查配置参数"] +CheckConfig --> IsConfigValid{"配置有效?"} +IsConfigValid --> |否| ReturnNull["返回空值"] +IsConfigValid --> |是| ReturnFixedValue["返回固定值"] +ReturnFixedValue --> End([结束]) +ReturnNull --> End +``` + +**Diagram sources ** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java#L1-L62) + +### 历史平均值计算策略 + +历史平均值计算策略基于历史数据表`dv_actual_values`中的实际值进行计算。系统支持多种时间范围的平均值计算,包括日均值、周均值、月均值、最近7天均值和最近30天均值。 + +#### 日均值计算 + +日均值计算策略通过`DailyAvg`类实现,根据不同的执行引擎(Spark、Flink、Local)调用相应的SQL脚本生成器获取执行SQL。 + +```mermaid +sequenceDiagram +participant User as "用户" +participant DailyAvg as "DailyAvg" +participant Connector as "ConnectorFactory" +participant Script as "MetricScript" +User->>DailyAvg : getExecuteSql(inputParameter) +DailyAvg->>DailyAvg : 获取引擎类型 +DailyAvg->>Connector : getConnectorFactory(engineType) +Connector-->>DailyAvg : 返回Connector实例 +DailyAvg->>Script : dailyAvg(uniqueKey) +Script-->>DailyAvg : 返回SQL语句 +DailyAvg-->>User : 返回执行SQL +``` + +**Diagram sources ** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L1-L76) +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java#L1-L35) + +#### 周均值计算 + +周均值计算策略通过`WeeklyAvg`类实现,使用SQL函数计算当前周的起始日期,然后对本周内的历史数据进行平均值计算。 + +```mermaid +flowchart TD +Start([开始]) --> GetDate["获取当前日期"] +GetDate --> CalculateWeekStart["计算周起始日期"] +CalculateWeekStart --> BuildSQL["构建SQL查询"] +BuildSQL --> ExecuteQuery["执行查询"] +ExecuteQuery --> CalculateAvg["计算平均值"] +CalculateAvg --> ReturnResult["返回结果"] +ReturnResult --> End([结束]) +``` + +**Diagram sources ** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java#L1-L76) + +#### 月均值计算 + +月均值计算策略通过`SparkMonthlyAvg`类实现,使用日期格式化函数获取当前月的起始日期,然后对本月内的历史数据进行平均值计算。 + +```mermaid +flowchart TD +Start([开始]) --> GetDate["获取当前日期"] +GetDate --> FormatMonthStart["格式化月起始日期"] +FormatMonthStart --> BuildSQL["构建SQL查询"] +BuildSQL --> ExecuteQuery["执行查询"] +ExecuteQuery --> CalculateAvg["计算平均值"] +CalculateAvg --> ReturnResult["返回结果"] +ReturnResult --> End([结束]) +``` + +**Diagram sources ** +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java#L1-L67) + +#### 最近7天和最近30天均值计算 + +最近7天和最近30天均值计算策略分别通过`SparkLast7DayAvg`和`SparkLast30DayAvg`类实现,使用日期减法函数计算时间范围,然后对指定时间范围内的历史数据进行平均值计算。 + +```mermaid +flowchart TD +Start([开始]) --> GetDate["获取当前日期"] +GetDate --> CalculateRange["计算时间范围"] +CalculateRange --> BuildSQL["构建SQL查询"] +BuildSQL --> ExecuteQuery["执行查询"] +ExecuteQuery --> CalculateAvg["计算平均值"] +CalculateAvg --> ReturnResult["返回结果"] +ReturnResult --> End([结束]) +``` + +**Diagram sources ** +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java#L1-L67) +- [SparkLast30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast30DayAvg.java#L1-L67) + +### 表行数计算策略 + +表行数计算策略通过`TableTotalRows`类实现,使用SQL的`COUNT(1)`函数计算指定表的总行数。该策略支持通过`filter`参数添加查询条件。 + +```mermaid +flowchart TD +Start([开始]) --> GetTable["获取表名"] +GetTable --> CheckFilter["检查过滤条件"] +CheckFilter --> HasFilter{"存在过滤条件?"} +HasFilter --> |是| AddWhere["添加WHERE子句"] +HasFilter --> |否| BuildBasicSQL["构建基础SQL"] +AddWhere --> BuildSQL["构建完整SQL"] +BuildBasicSQL --> BuildSQL +BuildSQL --> ExecuteQuery["执行查询"] +ExecuteQuery --> ReturnCount["返回行数"] +ReturnCount --> End([结束]) +``` + +**Diagram sources ** +- [TableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-table-rows\src\main\java\io\datavines\metric\expected\plugin\TableTotalRows.java#L1-L76) + +## 性能优化机制 + +### 缓存策略 + +系统通过`dv_actual_values`表存储历史实际值数据,实现了数据的持久化缓存。该表结构设计合理,包含`job_execution_id`、`metric_unique_key`、`actual_value`、`data_time`等关键字段,支持高效的时间范围查询。 + +```mermaid +erDiagram +dv_actual_values { +string job_execution_id PK +string metric_unique_key PK +decimal actual_value +timestamp data_time PK +string unique_code +timestamp create_time +timestamp update_time +} +``` + +**Diagram sources ** +- [MetricConstants.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\MetricConstants.java#L1-L64) + +### 增量计算 + +系统采用增量计算机制,每次计算预期值时只查询指定时间范围内的历史数据,避免了全量数据扫描。通过合理的索引设计(如`data_time`字段的索引),确保了时间范围查询的高效性。 + +### 并行处理 + +系统支持多种执行引擎(Spark、Flink、Local),可以根据数据规模和计算复杂度选择合适的执行引擎。对于大规模数据计算,可以利用Spark或Flink的分布式计算能力实现并行处理。 + +```mermaid +graph TD +InputData[输入数据] --> EngineSelector[引擎选择器] +EngineSelector --> |大规模数据| SparkEngine[Spark引擎] +EngineSelector --> |流式数据| FlinkEngine[Flink引擎] +EngineSelector --> |小规模数据| LocalEngine[Local引擎] +SparkEngine --> ParallelProcessing[并行处理] +FlinkEngine --> StreamProcessing[流式处理] +LocalEngine --> SequentialProcessing[顺序处理] +ParallelProcessing --> Output[输出结果] +StreamProcessing --> Output +SequentialProcessing --> Output +``` + +**Diagram sources ** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L1-L76) + +## 扩展接口说明 + +### 预期值接口 + +`ExpectedValue`接口定义了预期值计算的核心方法,为扩展新的计算策略提供了标准接口。 + +```java +public interface ExpectedValue { + String getName(); + String getZhName(); + String getKey(Map inputParameter); + String getExecuteSql(Map inputParameter); + String getOutputTable(Map inputParameter); + boolean isNeedDefaultDatasource(); + void prepare(Map config); +} +``` + +**Section sources** +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java#L1-L65) + +### 抽象基类 + +`AbstractExpectedValue`类提供了通用的连接器工厂获取方法,简化了子类的实现。 + +```java +public abstract class AbstractExpectedValue implements ExpectedValue { + protected ConnectorFactory getConnectorFactory(Map inputParameter) { + String srcConnectorType = inputParameter.get("src_connector_type"); + return PluginLoader.getPluginLoader(ConnectorFactory.class).getOrCreatePlugin(srcConnectorType); + } + + protected ConnectorFactory getConnectorFactory(String connectorType) { + return PluginLoader.getPluginLoader(ConnectorFactory.class).getOrCreatePlugin(connectorType); + } +} +``` + +**Section sources** +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java#L1-L35) + +## 容错与异常处理 + +### 异常处理机制 + +系统通过`DataVinesException`类统一处理异常,确保了错误信息的一致性和可追溯性。在`DailyAvg`等类中,当遇到不支持的引擎类型时会抛出明确的异常信息。 + +```mermaid +flowchart TD +Start([开始]) --> Execute["执行计算"] +Execute --> HasError{"发生异常?"} +HasError --> |是| CatchException["捕获异常"] +CatchException --> LogError["记录错误日志"] +LogError --> ThrowCustomException["抛出DataVinesException"] +ThrowCustomException --> HandleError["错误处理"] +HasError --> |否| ReturnResult["返回结果"] +ReturnResult --> End([结束]) +HandleError --> End +``` + +**Diagram sources ** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L1-L76) + +### 容错设计 + +系统在多个层面实现了容错设计: +1. **配置检查**:在`prepare`方法中检查配置参数的有效性 +2. **默认值处理**:对于可选参数提供合理的默认值 +3. **空值处理**:对可能为空的结果进行空值检查和处理 +4. **引擎兼容性**:通过条件判断支持多种执行引擎 + +## 计算策略配置参数 + +### 通用配置参数 + +| 参数名称 | 类型 | 描述 | 是否必需 | +|--------|-----|------|--------| +| `src_connector_type` | 字符串 | 源数据连接器类型 | 是 | +| `engine_type` | 字符串 | 执行引擎类型 | 是 | +| `metric_unique_key` | 字符串 | 指标唯一键 | 是 | +| `filter` | 字符串 | 查询过滤条件 | 否 | + +### 特定策略配置参数 + +#### 固定值策略 +- 无特定配置参数,直接使用预设值 + +#### 表行数策略 +- `table`:指定要计算行数的表名 +- `filter`:可选的查询过滤条件 + +#### 历史平均值策略 +- `data_time`:计算基准时间 +- `unique_code`:数据唯一编码 + +**Section sources** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L1-L76) +- [TableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-table-rows\src\main\java\io\datavines\metric\expected\plugin\TableTotalRows.java#L1-L76) +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java#L1-L62) + +## 结论 + +本文档详细描述了数据质量平台中预期值计算机制的实现原理和使用场景。系统通过插件化架构实现了多种预期值计算策略,包括固定值、历史平均值和表行数等。每种策略都有明确的适用条件和配置参数,能够满足不同业务场景的需求。 + +性能优化方面,系统通过缓存策略、增量计算和并行处理机制确保了计算效率。扩展接口设计合理,支持自定义计算逻辑的开发。容错机制完善,能够有效处理各种异常情况。 + +未来可以考虑增加更多计算策略,如移动平均、加权平均等,以满足更复杂的业务需求。同时,可以进一步优化查询性能,如引入更智能的索引策略和查询优化器。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\351\252\214\350\257\201\346\265\201\347\250\213.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\351\252\214\350\257\201\346\265\201\347\250\213.md" new file mode 100644 index 00000000..1020a6db --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\347\273\223\346\236\234\351\252\214\350\257\201/\351\252\214\350\257\201\346\265\201\347\250\213.md" @@ -0,0 +1,348 @@ +# 验证流程 + + +**本文档引用的文件** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [LocalSingleTableMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java) +- [LocalMultiTableAccuracyMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalMultiTableAccuracyMetricBuilder.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [JobExecutionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionInfo.java) +- [JobCheckState.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobCheckState.java) +- [DataQualityLevel.java](file://datavines-server/src/main/java/io/datavines/server/enums/DataQualityLevel.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [MetricExecutionResult.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricExecutionResult.java) +- [JobExecutionResult.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java) +- [SinkSqlBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/SinkSqlBuilder.java) + + +## 目录 +1. [引言](#引言) +2. [验证流程概述](#验证流程概述) +3. [核心组件分析](#核心组件分析) +4. [验证流程时序图](#验证流程时序图) +5. [状态管理机制](#状态管理机制) +6. [结果存储结构](#结果存储结构) +7. [可扩展性设计](#可扩展性设计) +8. [性能监控与优化](#性能监控与优化) +9. [结论](#结论) + +## 引言 + +数据质量验证流程是数据质量管理系统的核心功能,负责从任务执行到结果评估的完整验证过程。该流程通过任务调度器、执行引擎和结果存储组件的协作,实现对数据质量的全面监控和评估。本文档详细描述了验证流程的各个阶段,包括任务执行、结果提取、预期值获取、比较评估、状态管理和结果存储等关键环节。 + +## 验证流程概述 + +数据质量验证流程从任务执行开始,经过结果提取、预期值获取、比较评估等多个阶段,最终完成验证结果的存储和状态更新。整个流程涉及多个核心组件的协作,包括任务调度器、执行引擎、结果存储等。 + +验证流程的主要步骤包括: +1. 任务执行:执行引擎根据任务配置执行数据质量检查 +2. 结果提取:从执行结果中提取实际值 +3. 预期值获取:根据配置获取预期值 +4. 比较评估:将实际值与预期值进行比较,评估验证结果 +5. 状态管理:根据评估结果更新任务状态 +6. 结果存储:将验证结果存储到指定位置 + +```mermaid +flowchart TD +A[任务执行] --> B[结果提取] +B --> C[预期值获取] +C --> D[比较评估] +D --> E[状态管理] +E --> F[结果存储] +``` + +**图表来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) + +## 核心组件分析 + +### JobResultValidator 组件 + +JobResultValidator 是验证流程的核心组件,负责接收执行结果、提取实际值、获取预期值并进行比较评估。该组件通过调用 MetricValidator 进行具体的比较评估,并根据评估结果更新任务状态。 + +```mermaid +classDiagram +class JobResultValidator { ++operateDqExecuteResult(JobExecutionRequest) void ++checkDqExecuteResult(JobExecutionResult) boolean ++sendErrorEmail(Long) void +-buildAlertMessage(List, MetricExecutionResult, String, String, boolean) String +-buildAlertSubject(MetricExecutionResult, boolean) String +-saveIssue(Long, String, String) void +} +class MetricValidator { ++isSuccess(MetricExecutionResult) boolean ++getQualityScore(MetricExecutionResult, boolean) BigDecimal +-getCompareResult(OperatorType, BigDecimal, BigDecimal) boolean +} +JobResultValidator --> MetricValidator : "使用" +JobResultValidator --> JobExecutionResult : "处理" +JobResultValidator --> JobExecutionRequest : "接收" +``` + +**图表来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) + +**本节来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java#L73-L227) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java#L33-L82) + +### 配置构建组件 + +配置构建组件负责构建验证任务的配置,包括实际值和预期值的存储配置。这些组件根据任务类型和配置参数,生成相应的存储配置。 + +```mermaid +classDiagram +class BaseJobConfigurationBuilder { ++getActualValueSourceConfig() SourceConfig ++getValidateResultDataSourceConfig(String) SourceConfig +} +class LocalSingleTableMetricBuilder { ++buildSinkConfigs() void +} +class LocalMultiTableAccuracyMetricBuilder { ++buildSinkConfigs() void ++buildTransformConfigs() void +} +BaseJobConfigurationBuilder <|-- LocalSingleTableMetricBuilder +BaseJobConfigurationBuilder <|-- LocalMultiTableAccuracyMetricBuilder +LocalSingleTableMetricBuilder --> SinkSqlBuilder : "使用" +LocalMultiTableAccuracyMetricBuilder --> SinkSqlBuilder : "使用" +``` + +**图表来源** +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [LocalSingleTableMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java) +- [LocalMultiTableAccuracyMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalMultiTableAccuracyMetricBuilder.java) + +**本节来源** +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L228-L251) +- [LocalSingleTableMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java#L44-L127) +- [LocalMultiTableAccuracyMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalMultiTableAccuracyMetricBuilder.java#L71-L155) + +## 验证流程时序图 + +验证流程的时序图展示了从任务执行到结果评估的完整流程,包括各个组件之间的交互顺序。 + +```mermaid +sequenceDiagram +participant 调度器 as 任务调度器 +participant 执行引擎 as 执行引擎 +participant JobResultValidator as JobResultValidator +participant MetricValidator as MetricValidator +participant 结果存储 as 结果存储 +调度器->>执行引擎 : 提交任务执行请求 +执行引擎->>执行引擎 : 执行数据质量检查 +执行引擎->>结果存储 : 存储实际值和预期值 +执行引擎->>JobResultValidator : 发送执行结果 +JobResultValidator->>JobResultValidator : 提取实际值和预期值 +JobResultValidator->>MetricValidator : 调用比较评估 +MetricValidator-->>JobResultValidator : 返回评估结果 +JobResultValidator->>JobResultValidator : 更新任务状态 +JobResultValidator->>结果存储 : 存储验证结果 +JobResultValidator-->>调度器 : 返回验证结果 +``` + +**图表来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [JobExecutionResult.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java) + +## 状态管理机制 + +验证流程的状态管理机制负责处理成功、失败和异常情况。系统定义了多种状态,包括成功、失败和未知状态,通过状态码进行管理。 + +```mermaid +stateDiagram-v2 +[*] --> 未知 +未知 --> 成功 : 验证通过 +未知 --> 失败 : 验证失败 +成功 --> 未知 : 重置 +失败 --> 未知 : 重置 +失败 --> 发送通知 : 失败策略 +``` + +**图表来源** +- [JobCheckState.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobCheckState.java) + +**本节来源** +- [JobCheckState.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobCheckState.java#L35-L74) + +### 状态转换逻辑 + +状态管理机制通过 JobCheckState 枚举类实现,包含以下状态: +- NONE(0): 未知状态 +- SUCCESS(1): 成功状态 +- FAILURE(2): 失败状态 + +当验证结果为成功时,状态设置为 SUCCESS;当验证结果为失败时,状态设置为 FAILURE。系统还支持失败策略,可以在验证失败时发送通知或执行其他操作。 + +## 结果存储结构 + +验证结果的存储结构设计用于高效存储和访问验证结果数据。系统将实际值、预期值和验证结果分别存储在不同的表中。 + +```mermaid +erDiagram +dv_actual_values { +string metric_name +string metric_dimension +string metric_type +string database_name +string table_name +string column_name +decimal actual_value +string expected_type +string result_formula +string operator +decimal threshold +string failure_strategy +timestamp create_time +timestamp update_time +} +dv_job_execution_result { +string metric_name +string metric_dimension +string metric_type +string database_name +string table_name +string column_name +decimal actual_value +decimal expected_value +decimal score +int state +string expected_type +string result_formula +string operator +decimal threshold +string failure_strategy +timestamp create_time +timestamp update_time +} +dv_actual_values ||--o{ dv_job_execution_result : "关联" +``` + +**图表来源** +- [SinkSqlBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/SinkSqlBuilder.java) +- [LocalSingleTableMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java) + +**本节来源** +- [SinkSqlBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/SinkSqlBuilder.java) +- [LocalSingleTableMetricBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java#L58-L73) + +### 数据访问模式 + +验证结果的数据访问模式主要包括: +1. 按任务执行ID查询验证结果 +2. 按数据源、数据库、表和列查询历史验证结果 +3. 按时间范围查询验证结果 +4. 按验证状态查询任务 + +系统通过索引优化查询性能,确保在大数据量情况下仍能快速响应查询请求。 + +## 可扩展性设计 + +验证流程的可扩展性设计支持自定义验证逻辑的接入,通过插件机制实现灵活的扩展。 + +```mermaid +classDiagram +class ExpectedValue { ++getName() String ++getZhName() String ++getKey(Map) String +} +class ResultFormula { ++getResult(BigDecimal, BigDecimal) BigDecimal ++getScore(BigDecimal, BigDecimal, boolean, MetricDirectionType) BigDecimal ++getResultFormat(boolean) String ++getSymbol() String ++getType() ResultFormulaType +} +class SqlMetric { ++getNameByLanguage(boolean) String ++getMetricType() MetricType ++getMetricDimension() MetricDimension ++getDirectionType() MetricDirectionType ++getInvalidateItems(Map) ExecuteSql +} +ExpectedValue <|-- FixValue +ExpectedValue <|-- DailyAvgValue +ExpectedValue <|-- Last7DayAvgValue +ResultFormula <|-- Count +ResultFormula <|-- Diff +ResultFormula <|-- Percentage +ResultFormula <|-- DiffPercentage +ResultFormula <|-- DiffActualExpected +SqlMetric <|-- ColumnAvgMetric +SqlMetric <|-- ColumnNullMetric +SqlMetric <|-- TableRowCountMetric +``` + +**图表来源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) + +**本节来源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) + +### 自定义验证逻辑接入 + +系统通过 SPI(Service Provider Interface)机制支持自定义验证逻辑的接入。用户可以通过实现以下接口来扩展验证功能: +1. ExpectedValue: 自定义预期值计算逻辑 +2. ResultFormula: 自定义结果计算公式 +3. SqlMetric: 自定义数据质量检查指标 + +插件加载器(PluginLoader)负责加载和管理这些插件,确保系统能够动态识别和使用新添加的验证逻辑。 + +## 性能监控与优化 + +验证流程的性能监控指标和优化策略确保系统在高负载情况下仍能稳定运行。 + +### 性能监控指标 + +系统监控以下关键性能指标: +- 任务执行时间 +- 验证结果存储时间 +- 数据库查询响应时间 +- 内存使用率 +- CPU使用率 + +```mermaid +flowchart TD +A[性能监控] --> B[收集指标] +B --> C[分析指标] +C --> D[报警阈值] +D --> E[优化建议] +E --> F[性能优化] +F --> G[持续监控] +``` + +**图表来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java) +- [JobExecutionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionInfo.java) + +**本节来源** +- [JobResultValidator.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java) +- [JobExecutionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionInfo.java) + +### 优化策略 + +系统采用以下优化策略提升性能: +1. 批量处理:将多个验证任务合并处理,减少系统开销 +2. 缓存机制:缓存常用数据,减少数据库查询次数 +3. 异步处理:将非关键操作异步化,提高响应速度 +4. 索引优化:为关键查询字段创建索引,提升查询性能 +5. 连接池:使用数据库连接池,减少连接创建开销 + +## 结论 + +数据质量验证流程通过精心设计的架构和组件协作,实现了从任务执行到结果评估的完整验证过程。系统通过 JobResultValidator 核心组件、灵活的配置构建机制、完善的状态管理、高效的结果存储结构和可扩展的插件设计,提供了强大的数据质量验证能力。 + +验证流程的时序图清晰地展示了各个组件之间的交互顺序,状态管理机制确保了任务状态的准确跟踪,结果存储结构设计考虑了数据访问的效率和便利性。系统的可扩展性设计支持自定义验证逻辑的接入,满足不同场景的需求。 + +通过性能监控指标和优化策略,系统能够在高负载情况下保持稳定运行。未来可以进一步优化批量处理算法,引入机器学习模型进行智能阈值调整,提升系统的智能化水平。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\346\200\247\350\203\275\344\274\230\345\214\226.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\346\200\247\350\203\275\344\274\230\345\214\226.md" new file mode 100644 index 00000000..d83b8c6c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\346\200\247\350\203\275\344\274\230\345\214\226.md" @@ -0,0 +1,322 @@ +# 性能优化 + + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [ThreadUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ThreadUtils.java) +- [NamedThreadFactory.java](file://datavines-server/src/main/java/io/datavines/server/utils/NamedThreadFactory.java) +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [DefaultDataSourceInfoUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/DefaultDataSourceInfoUtils.java) + + +## 目录 +1. [引言](#引言) +2. [调度风暴避免策略](#调度风暴避免策略) +3. [分布式环境下的负载均衡](#分布式环境下的负载均衡) +4. [调度线程池配置](#调度线程池配置) +5. [超时控制与失败重试](#超时控制与失败重试) +6. [数据库连接池优化](#数据库连接池优化) +7. [日志管理与监控](#日志管理与监控) +8. [性能调优检查清单](#性能调优检查清单) + +## 引言 + +DataVines 是一个数据质量服务管理平台,支持多种数据质量检查规则和执行引擎。本指南旨在提供提升调度系统效率和稳定性的最佳实践,涵盖调度优化、资源管理、线程池配置、超时控制、数据库连接池优化等多个方面,帮助用户构建高性能、高可用的数据质量监控系统。 + +## 调度风暴避免策略 + +为避免调度风暴,系统采用错峰执行和批量调度优化策略。通过配置合理的调度间隔和执行窗口,确保系统资源的平稳利用。 + +```mermaid +flowchart TD +A[调度请求] --> B{资源检查} +B --> |资源充足| C[执行调度任务] +B --> |资源不足| D[延迟执行] +C --> E[任务执行完成] +D --> F[等待资源释放] +F --> B +``` + +**图示来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L55-L62) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L80-L86) + +**本节来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L49-L87) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L59-L134) + +## 分布式环境下的负载均衡 + +在分布式环境下,系统通过注册中心实现节点间的负载均衡。每个节点根据自身资源状况和任务队列长度动态调整任务分配,确保整体负载均衡。 + +```mermaid +graph TB +subgraph "注册中心" +ZK[ZooKeeper] +end +subgraph "服务器节点" +S1[Server 1] +S2[Server 2] +S3[Server 3] +end +ZK --> S1 +ZK --> S2 +ZK --> S3 +S1 --> |获取任务| ZK +S2 --> |获取任务| ZK +S3 --> |获取任务| ZK +``` + +**图示来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L41-L45) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L51-L55) + +**本节来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L41-L45) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L51-L55) + +## 调度线程池配置 + +调度系统使用多个线程池来管理不同类型的任务执行,合理配置线程池参数对系统性能至关重要。 + +### 线程池配置参数 + +| 参数 | 描述 | 推荐值 | +|------|------|--------| +| corePoolSize | 核心线程数 | 根据CPU核心数设置 | +| maximumPoolSize | 最大线程数 | 根据系统资源设置 | +| keepAliveTime | 空闲线程存活时间 | 60秒 | +| workQueue | 工作队列容量 | 根据任务量设置 | + +```mermaid +classDiagram +class ThreadPoolConfig { ++int corePoolSize ++int maximumPoolSize ++long keepAliveTime ++TimeUnit unit ++BlockingQueue~Runnable~ workQueue ++ThreadFactory threadFactory ++RejectedExecutionHandler handler +} +class JobExecuteManager { ++ExecutorService executorService ++ExecutorService jobExecuteService ++LinkedBlockingQueue~CommandContext~ jobExecutionQueue ++LinkedBlockingQueue~JobExecutionResponseContext~ responseQueue +} +JobExecuteManager --> ThreadPoolConfig : "使用" +``` + +**图示来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L108-L111) +- [ThreadUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ThreadUtils.java#L49-L155) + +**本节来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L108-L111) +- [ThreadUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ThreadUtils.java#L49-L155) + +## 超时控制与失败重试 + +系统提供完善的超时控制和失败重试机制,确保任务执行的可靠性和稳定性。 + +### 超时策略配置 + +```mermaid +sequenceDiagram +participant Job as "调度任务" +participant Manager as "JobExecuteManager" +participant Timer as "HashedWheelTimer" +Job->>Manager : 提交执行请求 +Manager->>Timer : 注册超时任务 +Timer->>Timer : 等待超时 +alt 任务完成 +Job->>Manager : 返回执行结果 +Manager->>Timer : 取消超时任务 +else 超时未完成 +Timer->>Manager : 触发超时事件 +Manager->>Job : 执行kill操作 +end +``` + +**图示来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L91-L92) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L404-L425) + +### 失败重试策略 + +系统支持多种失败重试策略,通过枚举类型定义不同的重试行为。 + +```mermaid +classDiagram +class TimeoutStrategy { ++int code ++String description ++RETRY(0, "retry") ++WARN(1, "warn") ++getCode() int ++getDescription() String +} +class JobExecution { ++int retryTimes ++int retryInterval ++int timeout ++TimeoutStrategy timeoutStrategy +} +JobExecution --> TimeoutStrategy : "引用" +``` + +**图示来源** +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java#L24-L50) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L321-L331) + +**本节来源** +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java#L24-L50) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L321-L331) + +## 数据库连接池优化 + +系统使用HikariCP作为数据库连接池,通过合理配置连接池参数提升数据库访问性能。 + +### 连接池配置 + +```mermaid +erDiagram +HIKARI_CONFIG { +string driverClassName +string jdbcUrl +string username +string password +int maximumPoolSize +int minimumIdle +long connectionTimeout +long idleTimeout +long maxLifetime +string poolName +} +DATASOURCE { +string type +string url +string username +string password +string driver +int port +string host +string database +} +HIKARI_CONFIG ||--o{ DATASOURCE : "配置" +``` + +**图示来源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java#L59-L63) +- [DefaultDataSourceInfoUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/DefaultDataSourceInfoUtils.java#L45-L62) + +### 连接池管理 + +系统通过唯一键管理不同数据源的连接池,避免重复创建连接。 + +```mermaid +flowchart TD +A[获取数据源配置] --> B[生成唯一键] +B --> C{连接池是否存在?} +C --> |是| D[返回现有连接池] +C --> |否| E[创建新连接池] +E --> F[缓存连接池] +F --> D +``` + +**图示来源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java#L71-L97) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java#L133-L138) + +**本节来源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java#L59-L143) +- [DefaultDataSourceInfoUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/DefaultDataSourceInfoUtils.java#L45-L62) + +## 日志管理与监控 + +系统提供完善的日志管理和监控机制,便于问题诊断和性能分析。 + +### 日志配置 + +```mermaid +classDiagram +class JobExecutionLogDiscriminator { ++String key ++String logBase ++getDiscriminatingValue(ILoggingEvent) String ++getKey() String ++setKey(String) void ++getLogBase() String ++setLogBase(String) void +} +class JobExecutionLogFilter { ++Level level ++setLevel(String) void ++decide(ILoggingEvent) FilterReply +} +class LoggerUtils { ++String JOB_LOGGER_INFO_PREFIX ++String JOB_LOGGER_THREAD_NAME +} +JobExecutionLogDiscriminator --> LoggerUtils : "使用" +JobExecutionLogFilter --> LoggerUtils : "使用" +``` + +**图示来源** +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java#L30-L68) +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java#L27-L44) + +### 监控指标 + +系统通过Spring Boot Actuator暴露监控指标,便于集成监控系统。 + +```yaml +management: + endpoints: + web: + exposure: + include: '*' + metrics: + tags: + application: ${spring.application.name} +``` + +**图示来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L72-L80) + +**本节来源** +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java#L30-L68) +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java#L27-L44) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L72-L80) + +## 性能调优检查清单 + +### 配置检查清单 + +| 检查项 | 配置建议 | +|-------|---------| +| 调度线程池大小 | 根据CPU核心数和任务类型合理设置 | +| 数据库连接池大小 | 根据并发需求和数据库性能设置 | +| 任务超时时间 | 根据任务执行时间合理设置 | +| 失败重试次数 | 根据任务重要性和失败原因设置 | +| 日志级别 | 生产环境建议使用INFO级别 | +| 监控指标 | 确保关键指标已暴露 | + +### 常见性能问题诊断 + +1. **调度延迟**:检查系统资源使用情况,调整调度线程池大小 +2. **数据库连接耗尽**:检查连接池配置,优化数据库访问 +3. **任务执行超时**:分析任务执行时间,调整超时策略 +4. **内存溢出**:检查对象生命周期,优化内存使用 +5. **CPU使用率过高**:分析热点代码,优化算法效率 + +**本节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\347\224\237\345\221\275\345\221\250\346\234\237\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\347\224\237\345\221\275\345\221\250\346\234\237\347\256\241\347\220\206.md" new file mode 100644 index 00000000..e97d9d08 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\347\224\237\345\221\275\345\221\250\346\234\237\347\256\241\347\220\206.md" @@ -0,0 +1,372 @@ +# 生命周期管理 + + +**本文档引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) + + +## 目录 +1. [引言](#引言) +2. [调度任务生命周期概述](#调度任务生命周期概述) +3. [任务状态转换逻辑](#任务状态转换逻辑) +4. [任务操作实现机制](#任务操作实现机制) +5. [元数据持久化与查询](#元数据持久化与查询) +6. [系统组件交互](#系统组件交互) +7. [异常情况处理策略](#异常情况处理策略) +8. [生命周期状态转换图](#生命周期状态转换图) +9. [结论](#结论) + +## 引言 + +数据质量调度任务生命周期管理是Datavines系统的核心功能之一,负责管理数据质量检查任务从创建到销毁的完整生命周期。本系统通过分布式架构设计,实现了任务的创建、启动、暂停、恢复、更新和删除等操作,同时提供了完善的任务状态管理、元数据持久化和异常处理机制。 + +系统采用微服务架构,主要由服务器核心模块、调度器、执行引擎和注册中心等组件构成。服务器核心模块负责任务的生命周期管理,调度器负责任务的调度和分配,执行引擎负责任务的实际执行,注册中心负责节点的注册和故障转移。这种架构设计确保了系统的高可用性和可扩展性。 + +**本文档引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) + +## 调度任务生命周期概述 + +调度任务的生命周期从任务创建开始,经过提交、执行、完成或失败等阶段,最终到达销毁状态。整个生命周期由多个核心组件协同管理,确保任务能够按照预定的流程顺利执行。 + +在系统启动时,`DataVinesServer`类负责初始化所有核心组件。通过`@PostConstruct`注解标记的`initializeAndStart`方法,系统依次初始化公共属性、任务执行管理器、通用任务管理器、注册中心等关键组件。其中,`JobScheduler`负责数据质量任务的调度,`CommonTaskScheduler`负责通用任务的调度。 + +任务的生命周期管理主要通过`JobExecuteManager`类实现。该类维护了任务执行队列、未完成任务映射和响应队列,通过多线程机制处理任务的执行和响应。当任务被提交时,系统会创建`JobExecutionRequest`对象,包含任务执行所需的所有参数,并将其放入执行队列中等待处理。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L75-L108) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L77-L81) + +## 任务状态转换逻辑 + +调度任务的状态转换是生命周期管理的核心,系统定义了多种状态来精确描述任务的执行情况。这些状态通过`ExecutionStatus`枚举类进行管理,每个状态都有唯一的代码和描述信息。 + +主要任务状态包括: +- **已提交**(SUBMITTED_SUCCESS):任务已成功提交到系统,等待执行 +- **执行中**(RUNNING_EXECUTION):任务正在执行过程中 +- **准备暂停**(READY_PAUSE):任务已收到暂停请求,正在准备暂停 +- **暂停**(PAUSE):任务已暂停执行 +- **准备停止**(READY_STOP):任务已收到停止请求,正在准备停止 +- **停止**(STOP):任务已停止执行 +- **失败**(FAILURE):任务执行失败 +- **成功**(SUCCESS):任务执行成功 +- **强制终止**(KILL):任务被强制终止 + +状态转换遵循严格的规则,例如只有在"已提交"或"准备暂停"状态下才能暂停任务,只有在"执行中"状态下才能停止任务。系统通过`typeIsRunning()`、`typeIsSuccess()`、`typeIsFailure()`等方法提供状态判断功能,便于在业务逻辑中进行状态检查。 + +```mermaid +stateDiagram-v2 +[*] --> 已提交 +已提交 --> 执行中 : 开始执行 +执行中 --> 成功 : 执行完成 +执行中 --> 失败 : 执行错误 +执行中 --> 准备暂停 : 收到暂停请求 +准备暂停 --> 暂停 : 暂停完成 +执行中 --> 准备停止 : 收到停止请求 +准备停止 --> 停止 : 停止完成 +执行中 --> 强制终止 : 收到终止请求 +成功 --> [*] +失败 --> [*] +暂停 --> [*] +停止 --> [*] +强制终止 --> [*] +``` + +**Diagram sources** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java#L45-L56) + +**Section sources** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java#L86-L157) + +## 任务操作实现机制 + +调度任务的各种操作通过API接口和后端服务协同实现。系统提供了RESTful API接口,允许用户通过HTTP请求对任务进行管理操作。 + +### 任务创建与启动 + +任务创建通过`JobExecutionController`中的`submitDataQualityJob`方法实现。当用户提交任务时,系统会创建`SubmitJob`对象,包含任务的基本信息和执行参数。控制器将请求转发给`JobExecutionService`,由服务层处理任务的持久化和调度。 + +```mermaid +sequenceDiagram +participant 用户 as "用户" +participant 控制器 as "JobExecutionController" +participant 服务 as "JobExecutionService" +participant 调度器 as "JobScheduler" +participant 执行器 as "JobExecuteManager" +用户->>控制器 : POST /job/execution/submit/data-quality +控制器->>服务 : submitJob(submitJob) +服务->>服务 : 创建JobExecution对象 +服务->>服务 : 保存到数据库 +服务->>调度器 : 创建Command对象 +调度器->>调度器 : 将Command放入队列 +调度器->>控制器 : 返回任务ID +控制器->>用户 : 返回任务ID +loop 调度器轮询 +调度器->>调度器 : 获取待执行Command +调度器->>执行器 : addExecuteCommand(jobExecution) +执行器->>执行器 : 将任务放入执行队列 +end +``` + +**Diagram sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L57-L59) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L89-L113) + +### 任务暂停与恢复 + +目前系统主要通过"停止"和"强制终止"操作来中断任务执行。`JobExecutionController`提供了`killTask`方法,允许用户通过DELETE请求终止指定的任务执行。 + +当收到终止请求时,系统会创建一个`Command`对象,类型为`CommandType.KILL`,并将其放入命令队列。`JobScheduler`在轮询时会检查是否有针对本机的KILL命令,如果有,则调用`JobExecuteManager`的`addKillCommand`方法。 + +```mermaid +sequenceDiagram +participant 用户 as "用户" +participant 控制器 as "JobExecutionController" +participant 服务 as "JobExecutionService" +participant 调度器 as "JobScheduler" +participant 执行器 as "JobExecuteManager" +用户->>控制器 : DELETE /job/execution/kill/{executionId} +控制器->>服务 : killJob(executionId) +服务->>服务 : 创建KILL类型的Command +服务->>服务 : 保存Command到数据库 +服务->>控制器 : 返回结果 +控制器->>用户 : 返回结果 +loop 调度器轮询 +调度器->>服务 : listKillCommandByExecuteHost(executeHost) +服务->>调度器 : 返回KILL命令列表 +调度器->>执行器 : addKillCommand(killCommand.jobExecutionId) +执行器->>执行器 : 处理终止命令 +end +``` + +**Diagram sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L68-L70) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L69-L77) + +### 任务更新与删除 + +任务更新主要通过修改任务配置和重新提交来实现。系统没有提供直接的任务更新API,而是通过创建新的任务执行实例来反映配置变更。任务删除实际上是通过终止正在运行的任务来实现的,已完成的任务记录会保留在系统中作为历史数据。 + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L57-L77) + +## 元数据持久化与查询 + +调度任务的元数据通过关系型数据库进行持久化存储,系统使用MyBatis-Plus作为ORM框架,实现了数据的高效存取。 + +### 元数据存储结构 + +核心数据表包括: +- **job_execution**:存储任务执行实例,包含任务ID、状态、开始时间、结束时间等信息 +- **command**:存储调度命令,包含命令类型、优先级、任务执行ID等信息 +- **config**:存储系统配置,用于动态调整系统行为 + +### 元数据查询机制 + +系统提供了多种查询接口,支持按不同条件检索任务执行记录。`JobExecutionService`接口定义了`getById`、`listByJobId`、`getJobExecutionPage`等方法,支持精确查询、列表查询和分页查询。 + +```mermaid +classDiagram +class JobExecution { ++Long id ++String name ++ExecutionStatus status ++LocalDateTime startTime ++LocalDateTime endTime ++String executeHost ++String logPath ++String parameter ++String engineType ++Integer retryTimes ++Integer timeout +} +class Command { ++Long id ++CommandType type ++Priority priority ++Long jobExecutionId ++String parameter ++LocalDateTime createTime +} +class Config { ++String varKey ++String varValue ++LocalDateTime updateTime +} +JobExecution "1" -- "0..*" Command : has +JobExecution --> Config : references +``` + +**Diagram sources** +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) +- [Command.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Command.java) +- [Config.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Config.java) + +**Section sources** +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java#L30-L34) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L79-L83) + +## 系统组件交互 + +调度任务生命周期管理涉及多个系统组件的协同工作,各组件通过定义良好的接口进行交互,确保系统的松耦合和高内聚。 + +### 核心组件交互 + +```mermaid +graph TD +A[客户端] --> B[JobExecutionController] +B --> C[JobExecutionService] +C --> D[JobScheduler] +D --> E[JobExecuteManager] +E --> F[JobRunner] +F --> G[执行引擎] +D --> H[Register] +H --> I[Registry] +E --> J[JobExecutionCache] +K[JobExecutionFailover] --> E +L[CommonTaskScheduler] --> M[CommonTaskManager] +style A fill:#f9f,stroke:#333 +style G fill:#bbf,stroke:#333 +``` + +- **控制器层**(JobExecutionController):提供RESTful API接口,接收外部请求 +- **服务层**(JobExecutionService):处理业务逻辑,协调各组件工作 +- **调度器**(JobScheduler):负责任务的调度和分配,从命令队列获取待执行任务 +- **执行管理器**(JobExecuteManager):管理任务执行的整个过程,包括执行、监控和响应处理 +- **注册中心**(Register):管理集群节点,处理节点故障转移 +- **缓存**(JobExecutionCache):缓存正在执行的任务上下文,支持任务状态查询和故障恢复 + +### 交互流程 + +1. 客户端通过HTTP请求提交任务 +2. 控制器接收请求并调用服务层 +3. 服务层创建任务执行记录和调度命令 +4. 调度器轮询获取待执行命令 +5. 执行管理器接收任务并启动执行线程 +6. JobRunner加载执行引擎并运行任务 +7. 执行结果通过响应队列返回给执行管理器 +8. 执行管理器更新任务状态并通知相关组件 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L75-L108) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) + +## 异常情况处理策略 + +系统设计了完善的异常处理机制,确保在各种异常情况下仍能保持稳定运行。 + +### 系统重启后的任务恢复 + +当系统重启时,`Register`组件会执行故障恢复流程。在`start`方法中,系统会: +1. 获取当前服务器的地址信息 +2. 查询是否有需要故障转移的任务 +3. 将这些任务重新分配到当前活跃的服务器节点 +4. 更新任务的执行主机信息 + +```mermaid +flowchart TD +Start([系统启动]) --> AcquireLock["获取故障转移锁"] +AcquireLock --> QueryTasks["查询需要故障转移的任务"] +QueryTasks --> CheckTasks{"有任务需要恢复?"} +CheckTasks --> |是| UpdateTasks["更新任务执行主机"] +UpdateTasks --> AddToQueue["将任务添加到执行队列"] +AddToQueue --> ReleaseLock["释放故障转移锁"] +CheckTasks --> |否| ReleaseLock +ReleaseLock --> UpdateServerList["更新服务器列表信息"] +UpdateServerList --> End([系统就绪]) +``` + +**Diagram sources** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L113-L134) + +### 调度冲突处理 + +系统通过分布式锁机制处理调度冲突。`Register`类使用注册中心提供的`acquire`和`release`方法实现分布式锁,确保在故障转移过程中只有一个节点能够处理任务恢复。 + +当多个节点同时检测到某个节点失效时,它们都会尝试获取故障转移锁。只有成功获取锁的节点才能执行任务恢复操作,其他节点将等待或重试。这种机制避免了多个节点同时恢复同一任务导致的冲突。 + +### 任务执行超时处理 + +系统使用`HashedWheelTimer`实现任务执行超时检测。当任务开始执行时,会创建一个超时定时任务。如果在指定时间内没有收到任务完成的响应,定时任务将触发并调用`doKillCommand`方法强制终止任务。 + +```mermaid +sequenceDiagram +participant 执行器 as "JobExecuteManager" +participant 定时器 as "HashedWheelTimer" +participant 任务 as "JobRunner" +执行器->>定时器 : newTimeout(JobExecutionTimeoutTimerTask, timeout) +定时器->>定时器 : 启动倒计时 +任务->>执行器 : 执行完成 +执行器->>定时器 : 取消定时任务 +定时器->>执行器 : 定时任务已取消 +alt 超时未完成 +定时器->>执行器 : run(Timeout) +执行器->>执行器 : doKillCommand(jobExecutionId) +执行器->>任务 : kill() +end +``` + +**Diagram sources** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L91-L92) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L404-L425) + +**Section sources** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L137-L141) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L404-L425) + +## 生命周期状态转换图 + +以下是调度任务生命周期的完整状态转换图,展示了任务在不同状态之间的转换关系和触发条件。 + +```mermaid +stateDiagram-v2 +[*] --> 已提交 : 任务提交 +已提交 --> 执行中 : 开始执行 +执行中 --> 成功 : 执行完成且结果正确 +执行中 --> 失败 : 执行错误或结果不正确 +执行中 --> 准备暂停 : 收到暂停请求 +准备暂停 --> 暂停 : 暂停完成 +执行中 --> 准备停止 : 收到停止请求 +准备停止 --> 停止 : 停止完成 +执行中 --> 强制终止 : 收到终止请求 +执行中 --> 待提交 : 等待资源 +待提交 --> 执行中 : 资源可用 +成功 --> [*] : 生命周期结束 +失败 --> [*] : 生命周期结束 +暂停 --> [*] : 生命周期结束 +停止 --> [*] : 生命周期结束 +强制终止 --> [*] : 生命周期结束 +note right of 执行中 +可能的状态转换: +- 成功:正常完成 +- 失败:执行异常 +- 暂停:用户暂停 +- 停止:用户停止 +- 终止:强制中断 +- 待提交:资源不足 +end note +``` + +**Diagram sources** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) + +## 结论 + +Datavines系统的数据质量调度任务生命周期管理机制设计完善,通过分布式架构实现了高可用性和可扩展性。系统采用分层设计,各组件职责明确,通过定义良好的接口进行交互,确保了系统的松耦合和高内聚。 + +核心特点包括: +1. **完整的生命周期管理**:支持任务的创建、启动、暂停、恢复、更新和删除等操作 +2. **精确的状态控制**:通过多种状态精确描述任务的执行情况,支持复杂的状态转换逻辑 +3. **可靠的持久化机制**:使用关系型数据库持久化任务元数据,确保数据的可靠存储 +4. **高效的组件交互**:通过队列和缓存机制实现组件间的高效通信 +5. **完善的异常处理**:设计了系统重启恢复、调度冲突处理和超时处理等机制 + +该系统能够有效管理大规模数据质量检查任务,为数据质量管理提供了坚实的基础。未来可以进一步优化任务调度算法,增加更多状态监控指标,提升系统的智能化水平。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\350\260\203\345\272\246\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\350\260\203\345\272\246\347\255\226\347\225\245.md" new file mode 100644 index 00000000..7053dc5d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\350\260\203\345\272\246\347\255\226\347\225\245.md" @@ -0,0 +1,281 @@ +# 调度策略 + + +**本文档引用的文件** +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java) +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) +- [NhourCronImpl.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/impl/NhourCronImpl.java) +- [HourCronImpl.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/impl/HourCronImpl.java) +- [WeekCronImpl.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/impl/WeekCronImpl.java) + + +## 目录 +1. [引言](#引言) +2. [调度框架实现原理](#调度框架实现原理) +3. [调度类型详解](#调度类型详解) +4. [Cron表达式语法与示例](#cron表达式语法与示例) +5. [调度任务生命周期管理](#调度任务生命周期管理) +6. [依赖管理与资源竞争处理](#依赖管理与资源竞争处理) +7. [超时与失败重试策略](#超时与失败重试策略) +8. [性能优化建议](#性能优化建议) +9. [分布式环境下的调度一致性](#分布式环境下的调度一致性) +10. [总结](#总结) + +## 引言 +数据质量调度策略文档全面介绍了基于Quartz框架的质量检查任务调度机制。该系统通过Quartz实现任务的精确调度,支持一次性、固定频率和Cron表达式等多种调度类型,确保数据质量检查任务能够按时、高效地执行。系统还提供了完善的调度任务生命周期管理、依赖管理、优先级设置和资源竞争处理机制,以及超时策略和失败重试策略,确保调度过程的稳定性和可靠性。在分布式环境下,系统通过注册中心和容错机制保证调度的一致性和故障恢复能力。 + +## 调度框架实现原理 +数据质量调度系统基于Quartz框架实现,Quartz是一个功能强大的开源作业调度框架,能够为几乎任何类型的作业提供调度服务。系统通过`QuartzExecutors`类封装Quartz的核心功能,实现了任务的添加、删除和更新操作。 + +```mermaid +classDiagram +class QuartzExecutors { +-Scheduler scheduler +-ReadWriteLock lock ++addJob(Class, ScheduleJobInfo) ++deleteJob(ScheduleJobInfo) ++deleteAllJobs(Scheduler, String) ++isValid(String) ++listFutureCronRunTimes(String, Integer) +} +class ScheduleJobInfo { +-ScheduleJobType type +-CommonTaskType taskType +-Long datasourceId +-Long id +-String cronExpression +-LocalDateTime startTime +-LocalDateTime endTime +} +class JobScheduleServiceImpl { +-QuartzExecutors quartzExecutor ++addScheduleJob(JobScheduleCreateOrUpdate, JobSchedule, Job) ++update(JobScheduleCreateOrUpdate) ++deleteBySchedule(JobSchedule) +} +QuartzExecutors --> ScheduleJobInfo : "使用" +JobScheduleServiceImpl --> QuartzExecutors : "依赖" +``` + +**图源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java) + +**本节源码** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L58-L262) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java#L24-L56) + +## 调度类型详解 +系统支持三种主要的调度类型:一次性调度、固定频率调度和Cron表达式调度。每种调度类型都有其特定的使用场景和配置方式。 + +### 一次性调度 +一次性调度用于执行单次任务,任务在指定时间点执行一次后即完成。这种调度类型适用于需要在特定时间点执行的临时任务或初始化任务。 + +### 固定频率调度 +固定频率调度允许任务按照固定的间隔时间重复执行。系统提供了多种固定频率的实现,如每小时、每天等。例如,`HourCronImpl`类实现了每小时调度的功能,通过配置分钟数来确定每小时的具体执行时间。 + +```mermaid +classDiagram +class FunCron { +<> ++funcDeal(String) String ++getFuncName() String +} +class HourCronImpl { ++funcDeal(String) String ++getFuncName() String +} +class NhourCronImpl { ++funcDeal(String) String ++getFuncName() String +} +class WeekCronImpl { ++funcDeal(String) String ++getFuncName() String +} +FunCron <|-- HourCronImpl +FunCron <|-- NhourCronImpl +FunCron <|-- WeekCronImpl +``` + +**图源** +- [HourCronImpl.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/impl/HourCronImpl.java) +- [NhourCronImpl.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/impl/NhourCronImpl.java) +- [WeekCronImpl.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/impl/WeekCronImpl.java) + +### Cron表达式调度 +Cron表达式调度提供了最灵活的调度方式,允许用户通过Cron表达式定义复杂的调度模式。系统支持标准的Quartz Cron表达式语法,可以精确到秒级别,满足各种复杂的调度需求。 + +**本节源码** +- [HourCronImpl.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/impl/HourCronImpl.java#L37-L75) +- [NhourCronImpl.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/impl/NhourCronImpl.java#L38-L73) +- [WeekCronImpl.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/impl/WeekCronImpl.java#L38-L75) + +## Cron表达式语法与示例 +Cron表达式由六个或七个字段组成,分别表示秒、分钟、小时、日期、月份、星期和年份(可选)。每个字段可以使用数字、星号(*)、斜杠(/)、连字符(-)和逗号(,)等符号来定义具体的调度规则。 + +### Cron表达式语法 +- **秒(Seconds)**:0-59 +- **分钟(Minutes)**:0-59 +- **小时(Hours)**:0-23 +- **日期(Day of month)**:1-31 +- **月份(Month)**:1-12 或 JAN-DEC +- **星期(Day of week)**:1-7 或 SUN-SAT(1表示星期日) +- **年份(Year)**:可选,1970-2099 + +### 常见调度模式示例 +- **每小时**:`0 0 * * * ?` - 每小时的第0分钟第0秒执行 +- **每天凌晨**:`0 0 0 * * ?` - 每天的00:00:00执行 +- **每周一**:`0 0 0 ? * MON` - 每周一的00:00:00执行 +- **每月1号**:`0 0 0 1 * ?` - 每月1号的00:00:00执行 +- **每5分钟**:`0 */5 * * * ?` - 每5分钟执行一次 + +系统提供了`listFutureCronRunTimes`方法来验证Cron表达式的有效性,并计算未来的执行时间列表,帮助用户确认调度配置的正确性。 + +**本节源码** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L249-L261) + +## 调度任务生命周期管理 +调度任务的生命周期包括创建、启动、暂停、恢复和删除等操作。系统通过`JobScheduleServiceImpl`类提供了完整的生命周期管理接口。 + +### 创建调度任务 +创建调度任务时,系统会根据调度类型调用`QuartzExecutors`的`addJob`方法,将任务添加到Quartz调度器中。如果任务已存在,则更新其触发器配置。 + +### 启动与暂停 +系统通过`JobExecuteManager`类管理任务的执行状态。任务启动时,会将其添加到执行队列中;暂停时,会从队列中移除并停止执行。 + +### 恢复与删除 +恢复操作会重新将暂停的任务添加到执行队列中。删除操作则通过`QuartzExecutors`的`deleteJob`方法从调度器中移除任务。 + +```mermaid +sequenceDiagram +participant 用户 +participant JobScheduleServiceImpl +participant QuartzExecutors +participant Scheduler +用户->>JobScheduleServiceImpl : 创建调度任务 +JobScheduleServiceImpl->>QuartzExecutors : addJob() +QuartzExecutors->>Scheduler : 添加/更新任务 +Scheduler-->>QuartzExecutors : 操作结果 +QuartzExecutors-->>JobScheduleServiceImpl : 处理结果 +JobScheduleServiceImpl-->>用户 : 返回结果 +用户->>JobScheduleServiceImpl : 删除调度任务 +JobScheduleServiceImpl->>QuartzExecutors : deleteJob() +QuartzExecutors->>Scheduler : 删除任务 +Scheduler-->>QuartzExecutors : 操作结果 +QuartzExecutors-->>JobScheduleServiceImpl : 处理结果 +JobScheduleServiceImpl-->>用户 : 返回结果 +``` + +**图源** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) + +**本节源码** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L116-L197) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L74-L148) + +## 依赖管理与资源竞争处理 +系统通过`JobExecuteManager`类管理任务的执行依赖和资源竞争。`JobExecuteManager`维护了一个执行队列和一个未完成任务映射表,确保任务按序执行并避免资源冲突。 + +```mermaid +classDiagram +class JobExecuteManager { +-ConcurrentHashMap unFinishedJobExecutionMap +-LinkedBlockingQueue jobExecutionQueue +-ExecutorService jobExecuteService ++addExecuteCommand(JobExecution) ++addKillCommand(Long) ++processJobExecutionExecuteResponse(JobExecuteResponseCommand) +} +class JobExecutionRequest { ++Long jobExecutionId ++String jobExecutionName ++String engineType ++Map inputParameter +} +class CommandContext { ++CommandCode commandCode ++Long jobExecutionId ++JobExecutionRequest jobExecutionRequest +} +JobExecuteManager --> JobExecutionRequest : "管理" +JobExecuteManager --> CommandContext : "处理" +``` + +**图源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) + +**本节源码** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L72-L615) + +## 超时与失败重试策略 +系统通过`TimeoutStrategy`枚举定义了任务失败时的处理策略,支持重试(RETRY)和警告(WARN)两种模式。超时策略通过`HashedWheelTimer`实现,为每个任务设置超时定时器。 + +```mermaid +classDiagram +class TimeoutStrategy { +<> +RETRY(0, "retry") +WARN(1, "warn") +} +class JobExecutionTimeoutTimerTask { +-long jobExecutionId +-int retryTimes ++run(Timeout) +} +class HashedWheelTimer { ++newTimeout(TimerTask, long, TimeUnit) +} +JobExecutionTimeoutTimerTask --> TimeoutStrategy : "使用" +HashedWheelTimer --> JobExecutionTimeoutTimerTask : "调度" +``` + +**图源** +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) + +**本节源码** +- [TimeoutStrategy.java](file://datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java#L24-L31) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L91-L92) + +## 性能优化建议 +为避免调度风暴和实现负载均衡,建议采取以下措施: +1. **合理设置调度间隔**:避免过于频繁的调度,减少系统负载。 +2. **使用分布式锁**:在分布式环境下,通过分布式锁确保同一任务不会被多个节点重复执行。 +3. **动态调整线程池大小**:根据系统负载动态调整执行线程池的大小,提高资源利用率。 +4. **监控和告警**:建立完善的监控和告警机制,及时发现和处理调度异常。 + +## 分布式环境下的调度一致性 +在分布式环境下,系统通过注册中心(Registry)和容错机制保证调度的一致性和故障恢复能力。当某个节点宕机时,其他节点会通过竞争分布式锁获得容错资格,接管该节点上未完成的任务。 + +```mermaid +sequenceDiagram +participant 节点A +participant 节点B +participant 注册中心 +节点A->>注册中心 : 注册 +节点B->>注册中心 : 注册 +注册中心->>节点B : 节点A下线 +节点B->>注册中心 : 竞争分布式锁 +注册中心-->>节点B : 获取锁 +节点B->>节点B : 接管节点A的任务 +``` + +**图源** +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java) + +**本节源码** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L73-L109) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L43-L151) + +## 总结 +本文档全面介绍了数据质量调度系统的实现原理和配置方式。系统基于Quartz框架,支持多种调度类型,提供了完善的生命周期管理、依赖管理、超时和失败重试策略。在分布式环境下,通过注册中心和容错机制保证了调度的一致性和可靠性。通过合理的性能优化措施,系统能够高效、稳定地执行数据质量检查任务。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\350\260\203\345\272\246\347\261\273\345\236\213.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\350\260\203\345\272\246\347\261\273\345\236\213.md" new file mode 100644 index 00000000..501378d7 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\225\260\346\215\256\350\264\250\351\207\217/\350\260\203\345\272\246\347\255\226\347\225\245/\350\260\203\345\272\246\347\261\273\345\236\213.md" @@ -0,0 +1,371 @@ +# 调度类型 + + +**本文档引用的文件** +- [JobScheduleType.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobScheduleType.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java) +- [JobSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java) +- [MapParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/schedule/MapParam.java) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java) +- [index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Jobs/components/Schedule/index.tsx) + + +## 目录 +1. [介绍](#介绍) +2. [一次性调度](#一次性调度) +3. [固定频率调度](#固定频率调度) +4. [Cron表达式调度](#cron表达式调度) +5. [调度类型对比](#调度类型对比) +6. [代码实现示例](#代码实现示例) +7. [结论](#结论) + +## 介绍 + +DataVines数据质量检查系统提供了三种调度类型:一次性调度、固定频率调度和Cron表达式调度。这些调度类型为数据质量检查任务提供了灵活的执行方式,满足不同场景下的需求。系统基于Quartz调度框架实现任务调度功能,通过不同的调度策略来控制数据质量检查任务的执行时机和频率。 + +**调度类型** +- **一次性调度**:用于临时性的数据质量验证,任务执行一次后即完成 +- **固定频率调度**:按照预设的时间间隔周期性执行任务 +- **Cron表达式调度**:使用Cron表达式定义复杂的调度模式,支持精确到秒的调度配置 + +这些调度类型通过`JobScheduleType`枚举类进行定义,包含`CYCLE`(固定频率)、`CRONTAB`(Cron表达式)和`OFFLINE`(一次性)三种类型。调度配置信息存储在`dv_job_schedule`数据库表中,包含任务ID、调度类型、参数、Cron表达式、状态以及开始和结束时间等字段。 + +**Section sources** +- [JobScheduleType.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobScheduleType.java#L24-L30) +- [JobSchedule.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java#L31-L74) + +## 一次性调度 + +一次性调度(One-time Scheduling)是一种特殊的调度类型,主要用于临时性的数据质量验证场景。在DataVines系统中,一次性调度通过`JobScheduleType.OFFLINE`类型来表示,当调度状态设置为`false`时,表示该任务为一次性执行任务。 + +一次性调度的主要应用场景包括: +- **临时数据验证**:当需要对特定数据集进行即时质量检查时,可以创建一次性调度任务 +- **问题排查**:在发现数据质量问题后,可以快速创建一次性任务来验证修复效果 +- **数据迁移验证**:在数据迁移或系统升级后,进行一次性全面数据质量检查 +- **新数据源接入验证**:在接入新的数据源时,进行一次性全面质量评估 + +在系统实现上,一次性调度的处理逻辑相对简单。当任务被创建时,系统会立即执行该任务,而不会将其加入到周期性调度队列中。在`JobScheduleServiceImpl`的`updateJobScheduleParam`方法中,当调度类型为`OFFLINE`时,系统会将任务状态设置为`false`,表示该任务不会被周期性执行。 + +```mermaid +flowchart TD +Start([创建一次性调度任务]) --> SetStatus["设置调度状态为 false"] +SetStatus --> CheckType{"调度类型为 OFFLINE?"} +CheckType --> |是| ExecuteOnce["立即执行任务"] +CheckType --> |否| AddToScheduler["添加到调度器"] +ExecuteOnce --> Complete([任务执行完成]) +AddToScheduler --> Complete +``` + +**Diagram sources** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L258-L260) + +**Section sources** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L258-L260) +- [JobScheduleType.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobScheduleType.java#L30) + +## 固定频率调度 + +固定频率调度(Fixed Frequency Scheduling)允许用户按照预设的时间间隔周期性执行数据质量检查任务。在DataVines系统中,固定频率调度通过`JobScheduleType.CYCLE`类型来表示,系统支持多种预定义的时间间隔模式。 + +### 时间间隔配置方式 + +固定频率调度的时间间隔通过`MapParam`对象进行配置,包含以下参数: +- **cycle**:调度周期类型,如"hour"、"day"、"week"等 +- **parameter**:具体的调度参数,如小时、分钟等数值 +- **crontab**:生成的Cron表达式 + +系统通过策略模式实现不同周期类型的处理,`StrategyFactory`根据`cycle`参数获取相应的`FunCron`实现类来生成Cron表达式。例如,当`cycle`为"hour"时,系统会使用`HourCron`类来生成每小时执行的Cron表达式。 + +### 精度控制 + +固定频率调度的精度控制主要体现在以下几个方面: + +1. **时间粒度控制**:系统支持从分钟级到周级的不同时间粒度 +2. **起止时间控制**:通过`startTime`和`endTime`参数精确控制任务的执行时间段 +3. **时区处理**:系统会自动处理服务器时区与调度时区的转换,确保任务在正确的时间执行 + +在`JobScheduleServiceImpl`的`updateJobScheduleParam`方法中,当调度类型为`CYCLE`时,系统会验证参数的完整性,然后通过策略工厂获取相应的Cron生成器来生成最终的Cron表达式: + +```mermaid +flowchart TD +Start([固定频率调度配置]) --> ValidateParam["验证参数完整性"] +ValidateParam --> GetStrategy["通过StrategyFactory获取FunCron实现"] +GetStrategy --> GenerateCron["调用funcDeal方法生成Cron表达式"] +GenerateCron --> SetCron["将生成的Cron表达式设置到JobSchedule"] +SetCron --> RegisterQuartz["注册到Quartz调度器"] +RegisterQuartz --> Complete([调度配置完成]) +``` + +**Diagram sources** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L230-L244) + +**Section sources** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L230-L244) +- [MapParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/schedule/MapParam.java#L23-L29) + +## Cron表达式调度 + +Cron表达式调度(Cron Expression Scheduling)提供了最灵活的调度方式,允许用户使用标准的Cron表达式来定义复杂的执行模式。在DataVines系统中,Cron表达式调度通过`JobScheduleType.CRONTAB`类型来表示。 + +### 语法规范 + +Cron表达式由六个或七个字段组成,每个字段代表一个时间单位。DataVines系统使用的Cron表达式格式如下: + +``` +秒 分 时 日 月 周 [年] +``` + +各字段的取值范围和特殊字符含义如下: + +| 字段 | 取值范围 | 特殊字符 | 含义 | +|------|--------|--------|------| +| 秒 | 0-59 | , - * / | 分隔符、范围、任意值、步长 | +| 分 | 0-59 | , - * / | 分隔符、范围、任意值、步长 | +| 时 | 0-23 | , - * / | 分隔符、范围、任意值、步长 | +| 日 | 1-31 | , - * / ? L W | 分隔符、范围、任意值、步长、无特定值、月末、工作日 | +| 月 | 1-12或JAN-DEC | , - * / | 分隔符、范围、任意值、步长 | +| 周 | 1-7或SUN-SAT | , - * / ? L # | 分隔符、范围、任意值、步长、无特定值、月末第几个周几 | +| 年 | (可选) | , - * / | 分隔符、范围、任意值、步长 | + +### 字段含义说明 + +- **`*`**:表示任意值,如分钟字段的`*`表示"每分钟" +- **`?`**:表示不指定值,通常用于日和周字段的互斥 +- **`-`**:表示范围,如`9-17`表示从9到17 +- **`,`**:表示多个值,如`1,3,5`表示1、3、5 +- **`/`**:表示增量,如`0/15`表示从0开始每15个单位执行一次 +- **`L`**:表示最后,如日字段的`L`表示"当月最后一天" +- **`W`**:表示工作日,如`15W`表示"距离15号最近的工作日" + +### 常见模式示例 + +以下是几种常见的Cron表达式模式及其含义: + +```mermaid +flowchart TD +subgraph "常见Cron表达式模式" +A["每小时执行: 0 0 * * * ?"] --> B["每天凌晨2点执行: 0 0 2 * * ?"] +B --> C["每周一上午9点执行: 0 0 9 ? * MON"] +C --> D["每月1号0点执行: 0 0 0 1 * ?"] +D --> E["每5分钟执行: 0 0/5 * * * ?"] +E --> F["工作日9点执行: 0 0 9 ? * MON-FRI"] +end +``` + +**Diagram sources** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L239-L262) + +在系统实现上,Cron表达式调度的验证和处理通过`QuartzExecutors`类完成。系统使用Quartz框架的`CronExpression.isValidExpression()`方法验证表达式的有效性,并在创建调度任务时进行验证: + +```java +public boolean isValid(String cronExpression) { + return CronExpression.isValidExpression(cronExpression); +} +``` + +当用户输入Cron表达式时,系统会调用`listFutureCronRunTimes`方法计算未来几次的执行时间,帮助用户验证表达式的正确性: + +```mermaid +flowchart TD +InputCron["用户输入Cron表达式"] --> Validate["调用isValid方法验证"] +Validate --> |有效| Calculate["调用listFutureCronRunTimes计算执行时间"] +Validate --> |无效| Error["返回错误信息"] +Calculate --> Display["显示未来10次执行时间"] +Display --> Complete([验证完成]) +``` + +**Diagram sources** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L250-L262) + +**Section sources** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L239-L262) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L245-L257) + +## 调度类型对比 + +以下是对三种调度类型的详细对比,包括优缺点和性能特征: + +### 调度类型对比表 + +| 特性 | 一次性调度 | 固定频率调度 | Cron表达式调度 | +|------|-----------|------------|-------------| +| **配置复杂度** | 简单 | 中等 | 复杂 | +| **灵活性** | 低 | 中等 | 高 | +| **适用场景** | 临时验证 | 周期性检查 | 复杂调度需求 | +| **维护成本** | 低 | 中等 | 高 | +| **错误风险** | 低 | 中等 | 高 | +| **性能开销** | 低 | 中等 | 中等 | +| **调试难度** | 低 | 中等 | 高 | + +### 优缺点分析 + +**一次性调度** +- **优点**: + - 配置简单,易于理解和使用 + - 执行后自动结束,无需手动停止 + - 适合临时性、一次性的数据质量验证 +- **缺点**: + - 缺乏灵活性,无法重复执行 + - 不能用于需要周期性检查的场景 + - 功能单一,仅适用于特定场景 + +**固定频率调度** +- **优点**: + - 配置相对简单,通过预定义选项选择时间间隔 + - 适合大多数周期性检查场景 + - 通过策略模式实现,易于扩展新的时间间隔类型 + - 系统自动处理Cron表达式生成,降低用户出错风险 +- **缺点**: + - 灵活性有限,只能选择预定义的时间间隔 + - 无法实现复杂的调度模式(如"每月最后一个工作日") + - 对于特殊需求需要开发新的策略类 + +**Cron表达式调度** +- **优点**: + - 极高的灵活性,可以定义几乎任何复杂的调度模式 + - 标准化语法,被广泛接受和使用 + - 适合复杂的业务需求和特殊调度场景 + - 支持精确到秒的调度精度 +- **缺点**: + - 语法复杂,学习成本高 + - 容易出错,一个字符的错误可能导致完全不同的执行模式 + - 调试困难,需要专门的工具验证表达式 + - 维护成本高,后续人员需要理解复杂的表达式 + +### 性能特征 + +从性能角度来看,三种调度类型的性能特征如下: + +1. **资源占用**:三种调度类型在资源占用上差异不大,主要开销在于Quartz调度器的定时检查 +2. **执行效率**:一次性调度在执行后立即释放资源,而周期性调度需要持续占用调度器资源 +3. **扩展性**:Cron表达式调度和固定频率调度都基于Quartz框架,具有良好的扩展性 +4. **可靠性**:系统通过数据库持久化调度配置,确保调度信息不会丢失 + +```mermaid +graph TD +subgraph "调度性能特征" +A[资源占用] --> A1["一次性: 低"] +A --> A2["固定频率: 中"] +A --> A3["Cron表达式: 中"] +B[执行效率] --> B1["一次性: 高"] +B --> B2["固定频率: 中"] +B --> B3["Cron表达式: 中"] +C[扩展性] --> C1["一次性: 低"] +C --> C2["固定频率: 高"] +C --> C3["Cron表达式: 高"] +D[可靠性] --> D1["一次性: 高"] +D --> D2["固定频率: 高"] +D --> D3["Cron表达式: 高"] +end +``` + +**Diagram sources** +- [JobScheduleType.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobScheduleType.java#L24-L30) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L57-L61) + +**Section sources** +- [JobScheduleType.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobScheduleType.java#L24-L30) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L57-L61) + +## 代码实现示例 + +本节通过实际代码示例展示不同类型调度任务的创建过程。 + +### 一次性调度创建示例 + +```mermaid +sequenceDiagram +participant UI as "前端界面" +participant Controller as "JobScheduleController" +participant Service as "JobScheduleServiceImpl" +participant Quartz as "QuartzExecutors" +UI->>Controller : POST /job/schedule/createOrUpdate +Controller->>Service : createOrUpdate(jobScheduleCreate) +Service->>Service : updateJobScheduleParam() +Service->>Service : JobScheduleType.of("offline") +Service->>Service : 设置状态为false +Service->>Service : 保存到数据库 +Service-->>Controller : 返回结果 +Controller-->>UI : 返回成功响应 +``` + +**Diagram sources** +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java#L48-L50) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L258-L260) + +### 固定频率调度创建示例 + +```mermaid +sequenceDiagram +participant UI as "前端界面" +participant Controller as "JobScheduleController" +participant Service as "JobScheduleServiceImpl" +participant Strategy as "StrategyFactory" +participant Quartz as "QuartzExecutors" +UI->>Controller : POST /job/schedule/createOrUpdate +Controller->>Service : createOrUpdate(jobScheduleCreate) +Service->>Service : updateJobScheduleParam() +Service->>Strategy : StrategyFactory.getByType("hour") +Strategy-->>Service : 返回HourCron实例 +Service->>Service : 调用funcDeal生成Cron表达式 +Service->>Quartz : addJob(DataQualityScheduleJob.class, scheduleJobInfo) +Quartz-->>Service : 调度任务创建成功 +Service-->>Controller : 返回结果 +Controller-->>UI : 返回成功响应 +``` + +**Diagram sources** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L230-L244) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L74-L148) + +### Cron表达式调度创建示例 + +```mermaid +sequenceDiagram +participant UI as "前端界面" +participant Controller as "JobScheduleController" +participant Service as "JobScheduleServiceImpl" +participant Quartz as "QuartzExecutors" +UI->>Controller : POST /job/schedule/createOrUpdate +Controller->>Service : createOrUpdate(jobScheduleCreate) +Service->>Service : updateJobScheduleParam() +Service->>Quartz : quartzExecutor.isValid(crontab) +Quartz-->>Service : 验证结果 +alt 验证通过 +Service->>Service : 设置Cron表达式 +Service->>Quartz : addJob(DataQualityScheduleJob.class, scheduleJobInfo) +Quartz-->>Service : 调度任务创建成功 +else 验证失败 +Service-->>Controller : 抛出SCHEDULE_CRON_IS_INVALID_ERROR +end +Service-->>Controller : 返回结果 +Controller-->>UI : 返回成功或错误响应 +``` + +**Diagram sources** +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L245-L257) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L239-L241) + +**Section sources** +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java#L48-L50) +- [JobScheduleServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java#L118-L128) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L74-L148) + +## 结论 + +DataVines系统提供的三种调度类型——一次性调度、固定频率调度和Cron表达式调度——为数据质量检查任务提供了全面的调度解决方案。每种调度类型都有其特定的适用场景和优势: + +1. **一次性调度**最适合临时性的数据质量验证场景,配置简单,执行后自动结束,适合快速验证和问题排查。 + +2. **固定频率调度**通过预定义的时间间隔选项,为大多数周期性检查场景提供了简单易用的解决方案。系统通过策略模式实现不同时间间隔的处理,既保证了易用性,又具有良好的扩展性。 + +3. **Cron表达式调度**提供了最高的灵活性,能够满足复杂的调度需求。虽然语法复杂,学习成本较高,但对于需要精确控制执行时间的场景是必不可少的。 + +在实际应用中,建议根据具体需求选择合适的调度类型: +- 对于临时验证和快速测试,使用一次性调度 +- 对于常规的周期性检查,使用固定频率调度 +- 对于复杂的业务需求和特殊调度模式,使用Cron表达式调度 + +系统通过统一的调度框架和清晰的代码结构,确保了三种调度类型的一致性和可靠性。前端界面与后端服务的良好集成,使得用户能够方便地创建和管理各种类型的调度任务。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\240\270\345\277\203\345\212\237\350\203\275.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\240\270\345\277\203\345\212\237\350\203\275.md" new file mode 100644 index 00000000..c8b99e3e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\345\212\237\350\203\275/\346\240\270\345\277\203\345\212\237\350\203\275.md" @@ -0,0 +1,360 @@ +# 核心功能 + + +**本文档引用的文件** +- [README.md](file://README.md) +- [README.zh-CN.md](file://README.zh-CN.md) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [CatalogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java) +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [DataQualityReportTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/report/DataQualityReportTaskRunner.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [JobExecuteBootstrap.java](file://datavines-runner/src/main/java/io/datavines/runner/JobExecuteBootstrap.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) + + +## 目录 +1. [简介](#简介) +2. [数据目录](#数据目录) +3. [数据质量](#数据质量) +4. [数据画像](#数据画像) +5. [功能协同与集成](#功能协同与集成) +6. [配置与管理](#配置与管理) +7. [监控与告警](#监控与告警) +8. [总结](#总结) + +## 简介 + +DataVines 是一个开源的一站式数据可观测性平台,提供元数据管理、数据质量监控、数据画像等核心功能。该平台旨在帮助用户全面了解和掌握数据资产,确保数据的准确性、完整性和一致性。DataVines 支持多种数据源,包括 MySQL、PostgreSQL、ClickHouse、Doris、StarRocks、Presto、Trino 等,并通过插件化设计实现了高度可扩展性。 + +平台的核心功能包括数据目录、数据质量和数据画像三大模块。数据目录模块负责构建和维护数据资产的元数据信息,支持定时获取数据源元数据、监听元数据变更以及标签管理。数据质量模块提供丰富的数据质量检查规则,支持单表列检查、自定义 SQL 检查、跨表准确性检查和两表值比对检查等多种检查类型,并支持定时任务和 SLA 告警。数据画像模块则通过定时执行数据探测,生成数据概览报告,支持自动识别列类型并匹配相应的数据概况指标,同时提供表行数趋势监控和数据分布视图。 + +DataVines 采用去中心化设计,Server 节点支持水平扩展以提高性能,作业具备自动容错能力,确保作业不丢失且不重复执行。平台依赖较少,易于部署,最小仅依赖 MySQL 即可启动项目,完成数据质量作业的检查。此外,DataVines 还支持 Web 页面配置检查作业、运行作业、查看作业执行日志、查看错误数据和检查结果,以及在线生成作业运行脚本,通过 `datavines-submit.sh` 提交作业,可与调度系统配合使用。 + +**Section sources** +- [README.md](file://README.md) +- [README.zh-CN.md](file://README.zh-CN.md) + +## 数据目录 + +数据目录是 DataVines 的核心功能之一,旨在构建和维护数据资产的元数据信息,帮助用户更好地理解和管理数据。该模块通过定时获取数据源的元数据来构建数据目录,并支持定时监听元数据变更情况,确保数据目录的实时性和准确性。此外,数据目录还支持标签管理,允许用户为元数据添加标签,以便于分类和检索。 + +### 业务价值与使用场景 + +数据目录的业务价值主要体现在以下几个方面: +- **数据资产管理**:通过集中管理数据源的元数据信息,帮助组织建立统一的数据资产视图,提升数据的可见性和可管理性。 +- **数据发现与探索**:用户可以通过数据目录快速查找和了解所需的数据表及其字段信息,提高数据使用的效率。 +- **数据治理**:支持元数据变更的监控,有助于及时发现和处理数据结构的变化,保障数据的一致性和完整性。 +- **合规性支持**:通过标签管理,可以对敏感数据进行标记,便于实施数据安全策略,满足合规要求。 + +典型使用场景包括: +- **数据湖/数据仓库管理**:在大规模数据环境中,数据目录可以帮助管理员和分析师快速定位和理解数据资产。 +- **数据迁移与整合**:在数据迁移或整合过程中,数据目录可以作为参考,确保数据结构的一致性。 +- **数据共享与协作**:团队成员可以通过数据目录共享数据信息,促进跨部门的数据协作。 + +### 技术实现 + +数据目录的技术实现主要包括以下几个关键组件: +- **元数据获取**:通过 `CatalogMetaDataFetchTaskRunner` 类实现,该类实现了 `Runnable` 接口,负责执行元数据获取任务。具体逻辑在 `CatalogMetaDataFetchExecutorImpl` 中定义,通过 JDBC 连接数据源,执行元数据查询语句,获取表结构、字段信息等元数据。 +- **元数据存储**:获取的元数据被存储在 DataVines 的数据库中,通常使用 MySQL 或 PostgreSQL 作为后端存储。元数据信息包括表名、字段名、数据类型、注释等。 +- **元数据变更监控**:通过定时任务定期执行元数据获取任务,比较新旧元数据的差异,记录变更历史。变更信息可以用于触发告警或通知相关人员。 +- **标签管理**:通过 `CatalogTagController` 类提供 REST API 接口,支持创建、更新和删除标签。标签可以应用于表、字段等元数据对象,帮助用户对数据进行分类和管理。 + +```mermaid +flowchart TD +A[数据源] --> B[元数据获取] +B --> C[元数据存储] +C --> D[元数据变更监控] +D --> E[标签管理] +E --> F[数据目录] +``` + +**Diagram sources** +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) + +**Section sources** +- [README.md](file://README.md) +- [README.zh-CN.md](file://README.zh-CN.md) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [CatalogTagController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/CatalogTagController.java) + +## 数据质量 + +数据质量是 DataVines 的核心功能之一,旨在确保数据在集成和处理过程中的准确性,是 DataOps 的核心组成部分。该模块提供了丰富的数据质量检查规则,支持多种检查类型,并可通过定时任务和 SLA 告警机制保障数据质量。 + +### 业务价值与使用场景 + +数据质量的业务价值主要体现在以下几个方面: +- **数据准确性**:通过内置的 27 个数据质量检查规则,确保数据的准确性和一致性,减少因数据错误导致的业务决策失误。 +- **数据完整性**:支持单表列检查、自定义 SQL 检查、跨表准确性检查和两表值比对检查等多种检查类型,覆盖数据质量的多个维度。 +- **自动化监控**:支持配置定时任务进行数据质量检查,减轻人工监控的负担,提高数据质量监控的效率。 +- **告警与通知**:支持 SLA 用于检查结果告警,当数据质量不达标时,及时通知相关人员,确保问题得到及时处理。 + +典型使用场景包括: +- **数据仓库质量监控**:在数据仓库中,通过数据质量模块定期检查数据的准确性、完整性和一致性,确保数据仓库的数据质量。 +- **ETL 流程验证**:在 ETL(Extract, Transform, Load)流程中,通过数据质量检查规则验证数据转换的正确性,确保数据在传输过程中的质量。 +- **数据治理**:通过数据质量检查结果,识别数据质量问题,推动数据治理工作的开展,提升整体数据管理水平。 + +### 技术实现 + +数据质量的技术实现主要包括以下几个关键组件: +- **检查规则**:DataVines 内置了 27 个数据质量检查规则,包括空值检查、非空检查、枚举检查等。这些规则通过 `MetricValidator` 类实现,该类提供了判断数据质量任务结果是否失败的方法。 +- **检查类型**:支持四种数据质量检查规则类型: + - **单表列检查**:针对单个表的特定列进行检查,如空值检查、非空检查等。 + - **单表自定义 SQL 检查**:通过自定义 SQL 语句对单个表进行复杂的数据质量检查。 + - **跨表准确性检查**:检查多个表之间的数据一致性,如主键外键关系的完整性。 + - **两表值比对检查**:比较两个表中的数据值,确保数据的一致性。 +- **定时任务**:通过 Quartz 调度框架实现定时任务,定期执行数据质量检查。`DataQualityScheduleJob` 类负责调度数据质量检查任务。 +- **SLA 告警**:当数据质量检查结果不满足 SLA 要求时,通过 `NotificationClient` 发送告警通知。`SlaNotificationMessage` 类定义了告警消息的结构,包括 SLA ID、主题和消息内容。 + +```mermaid +flowchart TD +A[数据源] --> B[数据质量检查] +B --> C[检查规则] +C --> D[单表列检查] +C --> E[单表自定义SQL检查] +C --> F[跨表准确性检查] +C --> G[两表值比对检查] +B --> H[定时任务] +H --> I[Quartz调度] +B --> J[SLA告警] +J --> K[NotificationClient] +K --> L[告警通知] +``` + +**Diagram sources** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) + +**Section sources** +- [README.md](file://README.md) +- [README.zh-CN.md](file://README.zh-CN.md) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) + +## 数据画像 + +数据画像是 DataVines 的核心功能之一,旨在通过定时执行数据探测,生成数据概览报告,帮助用户全面了解数据的分布和趋势。该模块支持自动识别列类型并匹配相应的数据概况指标,同时提供表行数趋势监控和数据分布视图。 + +### 业务价值与使用场景 + +数据画像的业务价值主要体现在以下几个方面: +- **数据洞察**:通过生成数据概览报告,帮助用户快速了解数据的整体情况,包括数据量、数据分布、数据趋势等。 +- **数据质量评估**:通过数据分布视图,识别数据中的异常值和离群点,评估数据质量。 +- **数据治理**:通过表行数趋势监控,及时发现数据量的异常变化,支持数据治理工作的开展。 +- **数据探索**:支持自动识别列类型并匹配相应的数据概况指标,帮助用户快速了解数据的特征,促进数据探索和分析。 + +典型使用场景包括: +- **数据仓库监控**:在数据仓库中,通过数据画像模块定期生成数据概览报告,监控数据量和数据分布的变化,确保数据仓库的健康状态。 +- **数据质量审计**:通过数据分布视图,识别数据中的异常值和离群点,进行数据质量审计,确保数据的准确性和一致性。 +- **数据探索与分析**:在数据分析过程中,通过数据画像模块快速了解数据的特征,支持数据探索和分析工作。 + +### 技术实现 + +数据画像的技术实现主要包括以下几个关键组件: +- **数据探测**:通过 `CatalogEntityInstanceService` 类提供的 `executeDataProfileJob` 方法,执行数据探测任务。该方法接收 `RunProfileRequest` 参数,包含数据源、表名、列名等信息,启动数据探测作业。 +- **数据概览报告**:数据探测任务完成后,生成数据概览报告。报告内容包括表行数、列的统计信息(如最大值、最小值、平均值、标准差等)、数据分布等。 +- **自动识别列类型**:通过 `ColumnInfo` 类解析列的元数据信息,自动识别列的数据类型(如数值型、字符串型、日期时间型等),并匹配相应的数据概况指标。 +- **表行数趋势监控**:通过 `listTableRecords` 方法,获取指定时间段内的表行数变化趋势,生成趋势图。 +- **数据分布视图**:通过 `getTop10Distribution` 方法,获取列的数据分布情况,生成分布图。 + +```mermaid +flowchart TD +A[数据源] --> B[数据探测] +B --> C[数据概览报告] +C --> D[表行数] +C --> E[列统计信息] +C --> F[数据分布] +B --> G[自动识别列类型] +G --> H[ColumnInfo] +B --> I[表行数趋势监控] +I --> J[listTableRecords] +B --> K[数据分布视图] +K --> L[getTop10Distribution] +``` + +**Diagram sources** +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [ColumnInfo.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ColumnInfo.java) + +**Section sources** +- [README.md](file://README.md) +- [README.zh-CN.md](file://README.zh-CN.md) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [ColumnInfo.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ColumnInfo.java) + +## 功能协同与集成 + +DataVines 的三大核心功能——数据目录、数据质量和数据画像——之间存在紧密的协同关系,共同构成了一个完整的数据可观测性平台。这些功能不仅各自独立发挥作用,还能相互配合,形成一个闭环的数据管理流程。 + +### 数据目录与数据质量的协同 + +数据目录为数据质量提供了基础的元数据信息。在配置数据质量检查规则时,用户可以从数据目录中选择需要检查的表和字段,确保检查规则的准确性和针对性。例如,在进行单表列检查时,用户可以通过数据目录查看表的结构和字段信息,选择合适的检查规则。此外,数据目录中的元数据变更监控功能可以及时发现表结构的变化,触发数据质量检查任务的重新配置,确保数据质量检查的持续有效性。 + +### 数据质量与数据画像的协同 + +数据质量检查结果可以作为数据画像的一部分,丰富数据概览报告的内容。例如,在生成数据概览报告时,可以将数据质量检查的结果(如空值率、非空率、枚举值分布等)纳入报告中,帮助用户全面了解数据的质量状况。此外,数据画像中的数据分布视图可以辅助数据质量检查,通过可视化的方式识别数据中的异常值和离群点,进一步验证数据质量检查的结果。 + +### 数据画像与数据目录的协同 + +数据画像生成的数据概览报告可以补充数据目录中的元数据信息,提供更丰富的数据洞察。例如,在数据目录中,除了基本的表结构和字段信息外,还可以展示表的行数趋势、列的统计信息和数据分布等。这些信息有助于用户更全面地了解数据的特征和变化趋势,支持数据治理和数据探索工作。 + +### 集成示例 + +假设某企业使用 DataVines 管理其数据仓库。首先,通过数据目录模块定时获取数据源的元数据信息,构建数据目录。然后,基于数据目录中的元数据信息,配置数据质量检查规则,定期执行数据质量检查任务。检查结果通过 SLA 告警机制通知相关人员。同时,通过数据画像模块定期生成数据概览报告,监控数据量和数据分布的变化。当发现数据量异常增加或数据分布出现离群点时,可以触发数据质量检查任务,进一步验证数据的准确性。最终,所有这些信息都被整合到数据目录中,形成一个完整的数据管理闭环。 + +```mermaid +flowchart TD +A[数据目录] --> B[元数据获取] +B --> C[数据质量] +C --> D[检查规则] +D --> E[定时任务] +E --> F[SLA告警] +C --> G[数据画像] +G --> H[数据探测] +H --> I[数据概览报告] +I --> J[表行数趋势] +I --> K[数据分布] +G --> L[自动识别列类型] +L --> M[ColumnInfo] +I --> N[数据目录] +N --> O[数据管理闭环] +``` + +**Diagram sources** +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) + +**Section sources** +- [README.md](file://README.md) +- [README.zh-CN.md](file://README.zh-CN.md) +- [CatalogEntityInstanceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/CatalogEntityInstanceService.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) + +## 配置与管理 + +DataVines 提供了丰富的配置和管理功能,支持用户通过 Web 页面或命令行工具进行配置和管理。这些功能涵盖了数据源管理、作业配置、调度管理、通知配置等多个方面,确保用户能够灵活地管理和使用平台。 + +### 数据源管理 + +数据源管理是 DataVines 的基础功能之一,支持用户添加、编辑和删除数据源。用户可以通过 Web 页面配置数据源的连接信息,包括数据库类型、主机地址、端口、用户名、密码等。平台支持多种数据源,包括 MySQL、PostgreSQL、ClickHouse、Doris、StarRocks、Presto、Trino 等。添加数据源后,平台会自动获取其元数据信息,构建数据目录。 + +### 作业配置 + +作业配置功能支持用户创建和管理数据质量检查作业和数据画像作业。用户可以通过 Web 页面选择数据源、表和字段,配置检查规则或数据探测参数。对于数据质量检查作业,用户可以选择检查类型(如单表列检查、单表自定义 SQL 检查等),设置检查频率和 SLA 告警条件。对于数据画像作业,用户可以配置数据探测的频率和范围,选择需要生成的报告内容。 + +### 调度管理 + +调度管理功能支持用户配置定时任务,定期执行数据质量检查和数据画像作业。平台使用 Quartz 调度框架实现定时任务,用户可以通过 Web 页面设置任务的执行频率(如每小时、每天、每周等)。调度任务可以与外部调度系统(如 Airflow、Cron)集成,实现更复杂的调度需求。 + +### 通知配置 + +通知配置功能支持用户配置告警通知,当数据质量检查结果不满足 SLA 要求时,通过邮件等方式通知相关人员。用户可以通过 Web 页面配置通知方式(如邮件、钉钉、企业微信等),设置通知接收人和通知内容。平台支持多种通知通道,包括邮件、钉钉、飞书、企业微信等。 + +### 管理工具 + +除了 Web 页面,DataVines 还提供了命令行工具 `datavines-submit.sh`,支持用户在线生成作业运行脚本,通过命令行提交作业。这种方式适用于与调度系统集成的场景,用户可以将生成的脚本提交到调度系统中,实现自动化作业调度。 + +```mermaid +flowchart TD +A[Web页面] --> B[数据源管理] +A --> C[作业配置] +A --> D[调度管理] +A --> E[通知配置] +F[命令行工具] --> G[datavines-submit.sh] +G --> H[作业运行脚本] +H --> I[调度系统] +``` + +**Diagram sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java) +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java) +- [datavines-submit.sh](file://bin/datavines-submit.sh) + +**Section sources** +- [README.md](file://README.md) +- [README.zh-CN.md](file://README.zh-CN.md) +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobScheduleController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java) +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java) +- [datavines-submit.sh](file://bin/datavines-submit.sh) + +## 监控与告警 + +监控与告警是 DataVines 的重要功能之一,旨在确保数据质量检查和数据画像作业的正常运行,并在出现问题时及时通知相关人员。平台提供了全面的监控和告警机制,支持用户通过 Web 页面查看作业执行日志、错误数据和检查结果,并配置 SLA 告警。 + +### 作业监控 + +作业监控功能支持用户查看作业的执行状态和日志。用户可以通过 Web 页面查看作业的执行历史,包括作业的开始时间、结束时间、执行状态(成功、失败、运行中等)和执行日志。对于失败的作业,用户可以查看详细的错误信息,定位问题原因。此外,平台还支持查看作业的执行趋势,帮助用户了解作业的执行情况。 + +### 错误数据存储 + +当数据质量检查发现错误数据时,平台支持将错误数据存储到指定的位置,便于后续分析和处理。用户可以配置错误数据的存储方式,包括 MySQL 和本地文件。对于使用 Local 执行引擎的作业,错误数据可以存储在本地文件中;对于使用 Spark 执行引擎的作业,错误数据可以存储在 MySQL 中。 + +### SLA 告警 + +SLA 告警功能支持用户配置数据质量检查的 SLA 条件,当检查结果不满足 SLA 要求时,通过邮件等方式通知相关人员。用户可以通过 Web 页面设置 SLA 条件,包括检查结果的阈值、告警频率和通知方式。平台支持多种通知通道,包括邮件、钉钉、飞书、企业微信等。告警消息包含 SLA ID、主题和详细信息,帮助用户快速了解问题的严重程度和影响范围。 + +### 告警管理 + +告警管理功能支持用户查看和管理告警记录。用户可以通过 Web 页面查看历史告警记录,包括告警时间、告警类型、告警内容和处理状态。对于已处理的告警,用户可以标记为已解决;对于未处理的告警,用户可以分配给相关人员进行处理。此外,平台还支持导出告警记录,便于后续分析和报告。 + +```mermaid +flowchart TD +A[作业执行] --> B[作业监控] +B --> C[执行状态] +B --> D[执行日志] +B --> E[执行趋势] +A --> F[错误数据存储] +F --> G[MySQL] +F --> H[本地文件] +A --> I[SLA告警] +I --> J[告警条件] +J --> K[阈值] +J --> L[告警频率] +J --> M[通知方式] +I --> N[告警消息] +N --> O[SLA ID] +N --> P[主题] +N --> Q[详细信息] +I --> R[告警管理] +R --> S[历史告警记录] +R --> T[处理状态] +R --> U[导出告警记录] +``` + +**Diagram sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [ErrorDataStorageController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/ErrorDataStorageController.java) +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java) +- [LogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LogController.java) + +**Section sources** +- [README.md](file://README.md) +- [README.zh-CN.md](file://README.zh-CN.md) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [ErrorDataStorageController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/ErrorDataStorageController.java) +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java) +- [LogController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LogController.java) + +## 总结 + +DataVines 是一个功能强大且易于使用的开源数据可观测性平台,提供了数据目录、数据质量和数据画像三大核心功能。这些功能不仅各自独立发挥作用,还能相互协同,形成一个完整的数据管理闭环。通过数据目录,用户可以构建和维护数据资产的元数据信息,提升数据的可见性和可管理性。通过数据质量,用户可以确保数据的准确性、完整性和一致性,减少因数据错误导致的业务决策失误。通过数据画像,用户可以全面了解数据的分布和趋势,支持数据治理和数据探索工作。 + +DataVines 采用去中心化设计,Server 节点支持水平扩展以提高性能,作业具备自动容错能力,确保作业不丢失且不重复执行。平台依赖较少,易于部署,最小仅依赖 MySQL 即可启动项目,完成数据质量作业的检查。此外,DataVines 还支持 Web 页面配置检查作业、运行作业、查看作业执行日志、查看错误数据和检查结果,以及在线生成作业运行脚本,通过 `datavines-submit.sh` 提交作业,可与调度系统配合使用。 + +总之,DataVines 为用户提供了一个全面的数据可观测性解决方案,帮助用户更好地理解和管理数据资产,确保数据的高质量和高可用性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/Doris\350\277\236\346\216\245\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/Doris\350\277\236\346\216\245\345\231\250.md" new file mode 100644 index 00000000..f1519c8d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/Doris\350\277\236\346\216\245\345\231\250.md" @@ -0,0 +1,477 @@ +# Doris连接器 + + +**本文档引用的文件** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java) +- [DorisDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDialect.java) +- [DorisConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java) +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java) +- [DorisConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java) +- [DorisParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java) +- [DorisExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisExecutor.java) +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/pom.xml) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +Doris连接器是DataVines项目中的一个专用连接器,用于与Apache Doris数据库进行交互。Doris是一个现代化的MPP(大规模并行处理)分析型数据库,支持实时数据导入、高并发查询和灵活的数据模型。 + +该连接器基于MySQL协议实现,通过继承MySQL连接器的功能,专门为Doris数据库提供了特定的适配和优化。它实现了DataVines连接器API的所有核心功能,包括数据库发现、表结构获取、列信息检索以及连接测试等。 + +## 项目结构 + +Doris连接器位于DataVines项目的插件架构中,采用模块化设计,与其他连接器保持一致的结构模式: + +```mermaid +graph TB +subgraph "Doris连接器模块" +A[DorisConnector] --> B[DorisDialect] +A --> C[DorisConfigBuilder] +A --> D[DorisDataSourceInfo] +E[DorisConnectorFactory] --> A +E --> F[DorisParameterConverter] +E --> G[DorisExecutor] +end +subgraph "基础连接器" +H[JdbcConnector] --> I[MysqlConnector] +I --> A +end +subgraph "外部依赖" +J[MySQL驱动] --> K[MySQL协议] +K --> L[Doris数据库] +end +A --> J +I --> J +``` + +**图表来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L40-L51) +- [DorisConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java#L21-L47) + +**章节来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L1-L251) +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/pom.xml#L1-L41) + +## 核心组件 + +Doris连接器由以下核心组件构成: + +### 主要连接器类 +- **DorisConnector**: 主要的连接器实现,继承自MySQL连接器 +- **DorisDialect**: 语法方言适配器,定义Doris特有的SQL语法支持 +- **DorisDataSourceInfo**: 数据源信息管理,负责构建Doris连接URL + +### 工厂和配置类 +- **DorisConnectorFactory**: 连接器工厂,创建各种相关组件实例 +- **DorisConfigBuilder**: 配置参数构建器,定义用户界面参数 +- **DorisParameterConverter**: 参数转换器,处理连接参数格式化 + +### 执行器类 +- **DorisExecutor**: 执行器实现,负责SQL语句执行和结果处理 + +**章节来源** +- [DorisConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java#L21-L47) +- [DorisConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java#L25-L59) + +## 架构概览 + +Doris连接器采用分层架构设计,基于DataVines的插件系统: + +```mermaid +graph TD +subgraph "应用层" +A[DataVines引擎] +end +subgraph "连接器层" +B[ConnectorFactory] +C[Connector] +D[Dialect] +E[Executor] +end +subgraph "配置层" +F[ConfigBuilder] +G[ParameterConverter] +H[DataSourceInfo] +end +subgraph "数据访问层" +I[JDBC连接] +J[MySQL驱动] +end +subgraph "目标系统" +K[Doris数据库] +end +A --> B +B --> C +B --> D +B --> E +B --> F +B --> G +B --> H +C --> I +H --> I +I --> J +J --> K +``` + +**图表来源** +- [DorisConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java#L21-L47) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L42-L64) + +### 连接流程序列图 + +```mermaid +sequenceDiagram +participant App as 应用程序 +participant Factory as 连接器工厂 +participant Connector as Doris连接器 +participant DataSource as 数据源信息 +participant JDBC as JDBC驱动 +participant Doris as Doris数据库 +App->>Factory : 创建连接器实例 +Factory->>Connector : 初始化连接器 +Factory->>DataSource : 构建数据源信息 +DataSource->>JDBC : 创建连接URL +Connector->>JDBC : 建立数据库连接 +JDBC->>Doris : 连接到Doris服务器 +Doris-->>JDBC : 返回连接状态 +JDBC-->>Connector : 返回连接对象 +Connector-->>App : 返回连接结果 +Note over Connector,Doris : 切换到指定目录 +Connector->>Doris : 执行SWITCH命令 +Doris-->>Connector : 返回目录切换结果 +``` + +**图表来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L72-L85) +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java#L29-L36) + +## 详细组件分析 + +### DorisConnector类分析 + +DorisConnector是整个连接器的核心实现,继承自MysqlConnector,主要扩展了以下功能: + +#### 核心方法实现 + +```mermaid +classDiagram +class JdbcConnector { ++getDatabases(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++testConnect(param) ConnectorResponse +-getConnection(dataSourceParam, param) Connection +} +class MysqlConnector { ++getDatasourceInfo(param) BaseJdbcDataSourceInfo ++getMetadataDatabases(connection) ResultSet +} +class DorisConnector { ++DORIS_DEFAULT_CATALOG : String ++getDatasourceInfo(param) BaseJdbcDataSourceInfo ++testConnect(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++getConnection(dataSourceParam, paramMap) Connection ++getColumns(connection, catalog, schema, tableName) ColumnInfo[] +-getMetadataTables(connection, schema) ResultSet +-getMetadataColumns(connection, catalog, schema, tableName, columnName) ResultSet +-switchCatalog(connection, catalogName) void +} +class DorisDataSourceInfo { ++getJdbcUrl() String +-appendCatalogOrDatabase(jdbcUrl) void +} +JdbcConnector <|-- MysqlConnector +MysqlConnector <|-- DorisConnector +DorisConnector --> DorisDataSourceInfo : 使用 +``` + +**图表来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L40-L51) +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java#L23-L36) + +#### 目录切换机制 + +Doris连接器实现了独特的目录切换功能,这是其与标准MySQL连接器的主要区别: + +```mermaid +flowchart TD +A[建立数据库连接] --> B{检查目录参数} +B --> |存在目录参数| C[使用指定目录] +B --> |不存在目录参数| D[使用默认目录] +C --> E[执行SWITCH目录命令] +D --> E +E --> F[验证目录切换结果] +F --> |成功| G[返回连接对象] +F --> |失败| H[抛出SQL异常] +H --> I[关闭连接并返回错误] +G --> J[连接建立完成] +``` + +**图表来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L206-L249) + +#### 表和列信息获取 + +Doris连接器通过重写元数据查询方法来适配Doris的特殊需求: + +**章节来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L87-L131) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L133-L167) + +### DorisDialect类分析 + +DorisDialect继承自MysqlDialect,主要修改了错误数据存储的支持性: + +#### 语法方言特性 + +| 特性 | 支持状态 | 说明 | +|------|----------|------| +| 错误数据存储 | 不支持 | Doris不支持将错误数据存储到单独的表中 | +| SQL语法兼容性 | 高度兼容 | 基于MySQL协议,语法高度相似 | +| 并行查询支持 | 完全支持 | 利用Doris的MPP架构优势 | +| 实时数据导入 | 完全支持 | 支持Stream Load等实时导入功能 | + +**章节来源** +- [DorisDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDialect.java#L19-L24) + +### DorisConfigBuilder类分析 + +DorisConfigBuilder负责定义用户界面的配置参数: + +#### 配置参数定义 + +```mermaid +graph LR +subgraph "Doris连接参数" +A[properties] --> B[连接属性] +C[catalog] --> D[目录名称] +E[database] --> F[数据库名称] +G[password] --> H[连接密码] +end +subgraph "默认值" +B --> I[useUnicode=true
characterEncoding=UTF-8
useSSL=false
serverTimezone=Asia/Shanghai
useInformationSchema=true] +D --> J[可选参数] +F --> K[必填参数] +H --> L[可选参数] +end +``` + +**图表来源** +- [DorisConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java#L28-L42) + +**章节来源** +- [DorisConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java#L25-L59) + +### DorisDataSourceInfo类分析 + +DorisDataSourceInfo负责构建Doris数据库的连接URL: + +#### URL构建逻辑 + +Doris连接URL的构建遵循特殊的格式规则: + +```mermaid +flowchart TD +A[开始构建URL] --> B[添加主机和端口] +B --> C{检查目录参数} +C --> |存在目录| D[添加目录到URL] +C --> |不存在| E[跳过目录] +D --> F{检查数据库参数} +F --> |存在数据库| G[添加数据库到URL] +F --> |不存在数据库| H[结束URL构建] +G --> I[添加目录和数据库分隔符] +I --> J[结束URL构建] +E --> H +H --> K[返回完整URL] +J --> K +``` + +**图表来源** +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java#L38-L60) + +**章节来源** +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java#L23-L61) + +## 依赖关系分析 + +Doris连接器的依赖关系体现了清晰的层次结构: + +```mermaid +graph TB +subgraph "外部依赖" +A[MySQL驱动] +B[Apache Commons Collections] +C[SLF4J日志框架] +D[JSON工具库] +end +subgraph "内部依赖" +E[JdbcConnector基类] +F[MysqlConnector基类] +G[Connector API接口] +H[DataSourceClient接口] +end +subgraph "Doris特有组件" +I[DorisConnector] +J[DorisDialect] +K[DorisDataSourceInfo] +L[DorisConfigBuilder] +M[DorisParameterConverter] +N[DorisExecutor] +end +I --> F +F --> E +E --> G +E --> H +I --> K +I --> L +I --> J +M --> I +N --> K +K --> A +I --> A +E --> B +E --> C +E --> D +``` + +**图表来源** +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/pom.xml#L32-L37) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L19-L36) + +### 继承关系图 + +```mermaid +classDiagram +class Connector { +<> ++getDatabases(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++testConnect(param) ConnectorResponse +} +class IJdbcDataSourceInfo { +<> ++getDatasourceInfo(param) BaseJdbcDataSourceInfo +} +class JdbcConnector { +<> ++dataSourceClient : DataSourceClient ++getDatabases(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++testConnect(param) ConnectorResponse +} +class MysqlConnector { ++getDatasourceInfo(param) BaseJdbcDataSourceInfo ++getMetadataDatabases(connection) ResultSet +} +class DorisConnector { ++DORIS_DEFAULT_CATALOG : String ++getDatasourceInfo(param) BaseJdbcDataSourceInfo ++testConnect(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++getConnection(dataSourceParam, paramMap) Connection ++getColumns(connection, catalog, schema, tableName) ColumnInfo[] +} +Connector <|.. JdbcConnector +IJdbcDataSourceInfo <|.. JdbcConnector +JdbcConnector <|-- MysqlConnector +MysqlConnector <|-- DorisConnector +``` + +**图表来源** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L42-L64) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java#L28-L45) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L40-L51) + +**章节来源** +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/pom.xml#L32-L37) +- [DorisConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java#L21-L47) + +## 性能考虑 + +### 连接池优化 + +Doris连接器在性能方面具有以下特点: + +1. **连接复用**: 通过继承JdbcConnector,自动获得连接池管理能力 +2. **元数据缓存**: 复用MySQL连接器的元数据查询优化 +3. **批量操作**: 支持大数据量的批量数据导入和查询 + +### 查询优化策略 + +```mermaid +flowchart TD +A[查询请求] --> B{检查查询类型} +B --> |简单查询| C[直接执行] +B --> |复杂查询| D[优化查询计划] +C --> E[快速响应] +D --> F[利用Doris优化器] +F --> G[返回优化结果] +G --> H[性能监控] +E --> H +``` + +### 内存管理 + +- **流式处理**: 对大结果集采用流式处理,避免内存溢出 +- **连接生命周期管理**: 自动管理连接的创建和销毁 +- **资源清理**: 确保所有数据库资源正确释放 + +## 故障排除指南 + +### 常见连接问题 + +| 问题类型 | 可能原因 | 解决方案 | +|----------|----------|----------| +| 连接超时 | 网络延迟或防火墙阻断 | 检查网络连通性和端口开放情况 | +| 认证失败 | 用户名或密码错误 | 验证Doris用户的认证信息 | +| 目录切换失败 | 目录不存在或权限不足 | 确认目录名称正确且有访问权限 | +| 元数据查询失败 | MySQL驱动版本不兼容 | 更新到兼容的MySQL驱动版本 | + +### 调试建议 + +1. **启用详细日志**: 在application.yaml中设置连接器日志级别 +2. **检查连接参数**: 验证所有必需参数的正确性 +3. **测试基础连接**: 使用testConnect方法验证基本连通性 +4. **监控资源使用**: 关注连接数和内存使用情况 + +**章节来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L54-L70) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L206-L249) + +## 结论 + +Doris连接器作为DataVines生态系统的重要组成部分,成功地将Apache Doris数据库集成到统一的数据质量平台中。通过继承MySQL连接器的设计模式,Doris连接器不仅保持了与现有系统的兼容性,还针对Doris的特性进行了专门的优化。 + +### 主要优势 + +1. **无缝集成**: 基于MySQL协议,实现零代码改造的Doris支持 +2. **功能完整**: 提供完整的数据库发现、表结构获取和元数据管理功能 +3. **性能优化**: 利用Doris的MPP架构优势,提供高效的查询性能 +4. **易于维护**: 清晰的代码结构和完善的测试覆盖 + +### 技术特色 + +- **目录切换机制**: 独特的目录管理功能,满足Doris的多租户需求 +- **参数化配置**: 灵活的配置选项,适应不同的部署环境 +- **错误处理**: 完善的异常处理和错误恢复机制 +- **资源管理**: 有效的连接管理和资源清理策略 + +Doris连接器为DataVines用户提供了稳定可靠的Doris数据库连接能力,是构建企业级数据质量解决方案的重要基础设施。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/Hive\350\277\236\346\216\245\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/Hive\350\277\236\346\216\245\345\231\250.md" new file mode 100644 index 00000000..ac068faa --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/Hive\350\277\236\346\216\245\345\231\250.md" @@ -0,0 +1,302 @@ +# Hive连接器 + + +**本文档引用的文件** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) +- [HiveDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDialect.java) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) +- [HiveConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConfigBuilder.java) +- [HiveExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveExecutor.java) +- [HiveDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceClient.java) +- [HiveMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveMetricScript.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) +- [JdbcDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDialect.java) +- [HiveSqlUtils.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\utils\HiveSqlUtils.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +Hive连接器是DataVines平台中用于连接和操作Apache Hive数据库的重要组件。该连接器实现了Hive特有的连接参数处理、HiveQL语法支持、Kerberos认证配置等功能,为大数据环境下的数据质量监控和分析提供了可靠的基础。本文档详细介绍了Hive连接器的实现细节,包括其核心组件、架构设计、安全配置和性能优化建议。 + +## 项目结构 +Hive连接器作为DataVines系统的一个插件,位于`datavines-connector-plugins`模块下的`datavines-connector-hive`子模块中。该结构遵循了DataVines的插件化设计原则,使得Hive连接器可以独立开发、测试和部署。 + +```mermaid +graph TD +subgraph "datavines-connector-plugins" +HiveConnector["datavines-connector-hive"] +HiveConnector --> JavaSrc["src/main/java"] +HiveConnector --> Resources["src/main/resources"] +JavaSrc --> io.datavines.connector.plugin +io.datavines.connector.plugin --> HiveConnector.java +io.datavines.connector.plugin --> HiveDataSourceInfo.java +io.datavines.connector.plugin --> HiveDialect.java +io.datavines.connector.plugin --> KerberosUtils.java +io.datavines.connector.plugin --> HiveConfigBuilder.java +io.datavines.connector.plugin --> HiveExecutor.java +io.datavines.connector.plugin --> HiveDataSourceClient.java +io.datavines.connector.plugin --> HiveMetricScript.java +Resources --> META-INF.plugins +META-INF.plugins --> ConnectorFactory +end +``` + +**图示来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) + +**本节来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) + +## 核心组件 +Hive连接器的核心组件包括HiveConnector、HiveDataSourceInfo、HiveDialect、KerberosUtils等类,它们共同实现了Hive数据库的连接、认证、SQL执行和结果处理功能。这些组件通过继承和扩展基础JDBC类,实现了Hive特有的功能需求。 + +**本节来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) + +## 架构概述 +Hive连接器的架构基于DataVines的插件化设计,通过实现Connector接口和继承基础JDBC类来提供Hive数据库的特定功能。连接器的核心是HiveConnector类,它负责管理连接、执行查询和处理结果。HiveDataSourceInfo类处理Hive特有的连接参数,HiveDialect类支持HiveQL语法,而KerberosUtils类则负责Kerberos认证的配置和初始化。 + +```mermaid +classDiagram +class HiveConnector { ++HiveConnector(DataSourceClient) ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo ++getMetadataColumns(DatabaseMetaData, String, String, String, String) ResultSet ++getMetadataTables(DatabaseMetaData, String, String) ResultSet ++testConnect(TestConnectionRequestParam) ConnectorResponse +} +class HiveDataSourceInfo { ++HiveDataSourceInfo(Map~String,String~) ++getAddress() String ++getDriverClass() String ++getType() String ++getSeparator() String +} +class HiveDialect { ++getDriver() String ++getPageFromResultSet(Statement, ResultSet, String, int, int) ResultList +} +class KerberosUtils { ++checkKerberosConfig(String, String, String) boolean ++getPrincipalListFromKeytab(String) String[] ++initKerberos(String, String, String) boolean +} +class HiveExecutor { ++HiveExecutor(DataSourceClient) ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo ++query(JdbcTemplate, String, int) ListWithQueryColumn +} +class HiveDataSourceClient { ++getConnection(BaseJdbcDataSourceInfo) Connection ++getConnection(Map~String,Object~, Logger) Connection +} +HiveConnector --> HiveDataSourceInfo : "使用" +HiveConnector --> HiveDialect : "使用" +HiveConnector --> KerberosUtils : "使用" +HiveExecutor --> HiveDataSourceInfo : "使用" +HiveDataSourceClient --> KerberosUtils : "使用" +HiveDataSourceClient --> JdbcDataSourceManager : "使用" +``` + +**图示来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) +- [HiveDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDialect.java) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) + +## 详细组件分析 + +### HiveConnector分析 +HiveConnector是Hive连接器的核心类,继承自JdbcConnector并实现了Connector接口。它负责管理Hive数据库的连接和查询执行。该类通过重写父类方法来提供Hive特有的功能,如元数据获取和连接测试。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant HiveConnector as "HiveConnector" +participant HiveDataSourceInfo as "HiveDataSourceInfo" +participant KerberosUtils as "KerberosUtils" +participant DriverManager as "DriverManager" +Client->>HiveConnector : testConnect(TestConnectionRequestParam) +HiveConnector->>HiveDataSourceInfo : getDatasourceInfo(paramMap) +HiveConnector->>KerberosUtils : checkKerberosConfig() +alt Kerberos配置有效 +KerberosUtils-->>HiveConnector : true +HiveConnector->>KerberosUtils : initKerberos() +else Kerberos配置无效 +KerberosUtils-->>HiveConnector : false +end +HiveDataSourceInfo->>HiveConnector : 返回HiveDataSourceInfo实例 +HiveConnector->>HiveDataSourceInfo : loadClass() +HiveConnector->>DriverManager : getConnection(jdbcUrl, user, password) +DriverManager-->>HiveConnector : Connection +HiveConnector-->>Client : ConnectorResponse +``` + +**图示来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) + +**本节来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) + +### HiveDataSourceInfo分析 +HiveDataSourceInfo类负责处理Hive特有的连接参数,继承自BaseJdbcDataSourceInfo。它实现了Hive连接URL的构建、驱动类名的获取和连接类型标识等核心功能。 + +```mermaid +classDiagram +class BaseJdbcDataSourceInfo { ++param Map~String,String~ ++getUser() String ++getPassword() String ++getHost() String ++getPort() String ++getCatalog() String ++getDatabase() String ++getSchema() String ++getProperties() String ++getDriverClass() String ++getType() String ++getJdbcUrl() String ++getConnection() Connection ++loadClass() void +} +class HiveDataSourceInfo { ++getAddress() String ++getDriverClass() String ++getType() String ++getSeparator() String +} +BaseJdbcDataSourceInfo <|-- HiveDataSourceInfo : "继承" +``` + +**图示来源** +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) + +**本节来源** +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) + +### HiveDialect分析 +HiveDialect类负责处理HiveQL语法和分区表的支持,继承自JdbcDialect。它重写了getPageFromResultSet方法,以支持Hive特有的分页查询语法。 + +```mermaid +flowchart TD +Start([开始]) --> GetPageFromResultSet["getPageFromResultSet()"] +GetPageFromResultSet --> BuildSQL["构建分页SQL: SELECT * FROM table LIMIT start, count"] +BuildSQL --> ExecuteSQL["执行SQL查询"] +ExecuteSQL --> GetResult["获取结果集"] +GetResult --> ProcessResult["处理结果"] +ProcessResult --> ReturnResult["返回ResultList"] +ReturnResult --> End([结束]) +``` + +**图示来源** +- [HiveDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDialect.java) +- [JdbcDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDialect.java) + +**本节来源** +- [HiveDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDialect.java) + +### Kerberos认证配置 +KerberosUtils类提供了Kerberos认证的配置和初始化功能。它检查Kerberos配置的有效性,并在需要时初始化Kerberos环境。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant HiveDataSourceClient as "HiveDataSourceClient" +participant KerberosUtils as "KerberosUtils" +participant HadoopUGI as "UserGroupInformation" +Client->>HiveDataSourceClient : getConnection() +HiveDataSourceClient->>KerberosUtils : checkKerberosConfig() +alt 配置有效 +KerberosUtils-->>HiveDataSourceClient : true +HiveDataSourceClient->>KerberosUtils : initKerberos() +KerberosUtils->>HadoopUGI : setConfiguration() +HadoopUGI-->>KerberosUtils : 配置成功 +KerberosUtils->>HadoopUGI : loginUserFromKeytab() +HadoopUGI-->>KerberosUtils : 登录成功 +KerberosUtils-->>HiveDataSourceClient : kerberosInit=true +else 配置无效 +KerberosUtils-->>HiveDataSourceClient : false +end +HiveDataSourceClient->>JdbcDataSourceManager : getDataSource() +JdbcDataSourceManager-->>HiveDataSourceClient : DataSource +HiveDataSourceClient->>DataSource : getConnection() +DataSource-->>HiveDataSourceClient : Connection +HiveDataSourceClient-->>Client : Connection +``` + +**图示来源** +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) +- [HiveDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceClient.java) + +**本节来源** +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) + +## 依赖分析 +Hive连接器依赖于多个核心组件和外部库,形成了一个完整的连接和查询执行体系。这些依赖关系确保了连接器能够正确处理Hive数据库的连接、认证和查询操作。 + +```mermaid +graph TD +HiveConnector --> HiveDataSourceInfo +HiveConnector --> HiveDialect +HiveConnector --> KerberosUtils +HiveExecutor --> HiveDataSourceInfo +HiveExecutor --> HiveSqlUtils +HiveDataSourceClient --> KerberosUtils +HiveDataSourceClient --> JdbcDataSourceManager +HiveDialect --> HiveSqlUtils +HiveConfigBuilder --> JdbcConfigBuilder +HiveMetricScript --> JdbcMetricScript +``` + +**图示来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) +- [HiveDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDialect.java) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) +- [HiveExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveExecutor.java) +- [HiveDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceClient.java) +- [HiveSqlUtils.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\utils\HiveSqlUtils.java) + +**本节来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) +- [HiveDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDialect.java) + +## 性能考虑 +Hive连接器在性能方面进行了多项优化,包括查询并行度控制、内存配置和连接池管理。HiveSqlUtils类中的query方法设置了默认的最大行数限制(DEFAULT_LIMIT=1000),防止大结果集导致内存溢出。同时,连接器通过JdbcDataSourceManager实现了连接池管理,提高了连接的复用效率。 + +在查询执行方面,连接器提供了分页查询支持,通过getPageFromResultSet方法实现了高效的分页查询。对于大数据量的查询,建议使用适当的LIMIT子句来限制返回结果的数量,避免对Hive服务器造成过大压力。 + +**本节来源** +- [HiveSqlUtils.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\utils\HiveSqlUtils.java) +- [HiveDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDialect.java) + +## 故障排除指南 +Hive连接器的常见问题主要集中在连接配置、Kerberos认证和查询执行三个方面。对于连接问题,首先检查HiveServer2的URL、端口和数据库名称是否正确。对于Kerberos认证问题,确保keytab文件路径、principal和krb5.conf文件配置正确,并且文件具有适当的读取权限。 + +在查询执行方面,如果遇到"Invalid query"错误,检查SQL语法是否符合HiveQL规范。对于性能问题,检查是否设置了适当的查询限制,并考虑优化Hive查询计划。日志文件是诊断问题的重要工具,连接器在执行过程中会记录详细的日志信息,包括查询执行时间和结果统计。 + +**本节来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [HiveDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceClient.java) +- [HiveSqlUtils.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\utils\HiveSqlUtils.java) + +## 结论 +Hive连接器通过精心设计的架构和实现,为DataVines平台提供了可靠的Hive数据库连接能力。它不仅支持标准的JDBC功能,还针对Hive的特性实现了Kerberos认证、HiveQL语法支持和性能优化。通过插件化的设计,Hive连接器可以轻松集成到DataVines生态系统中,为大数据环境下的数据质量管理提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/JDBC\350\277\236\346\216\245\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/JDBC\350\277\236\346\216\245\345\231\250.md" new file mode 100644 index 00000000..433420a8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/JDBC\350\277\236\346\216\245\345\231\250.md" @@ -0,0 +1,283 @@ +# JDBC连接器 + + +**本文档引用的文件** +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java) +- [JdbcDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDataSourceClient.java) +- [JdbcDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDialect.java) +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) +- [JdbcExecutorClient.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcExecutorClient.java) +- [JdbcExecutorClientManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcExecutorClientManager.java) +- [ConnectionUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\ConnectionUtils.java) +- [JdbcUrlParser.java](file://datavines-common\src\main\java\io\datavines\common\utils\JdbcUrlParser.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件](#核心组件) +3. [连接池管理](#连接池管理) +4. [连接测试与故障恢复机制](#连接测试与故障恢复机制) +5. [JdbcDataSourceClient统一管理](#jdbcdatasourceclient统一管理) +6. [JdbcDialect适配策略](#jdbcdialect适配策略) +7. [连接参数配置最佳实践](#连接参数配置最佳实践) +8. [性能优化建议](#性能优化建议) +9. [结论](#结论) + +## 引言 +JDBC连接器是DataVines平台中用于连接各种关系型数据库的核心组件。作为所有JDBC数据库的基础实现,它提供了一套统一的接口和机制来管理数据库连接、执行SQL语句以及处理不同数据库的特定行为。本文档详细阐述了JDBC连接器的架构设计、关键组件及其工作原理,重点介绍了连接池管理、连接测试、故障恢复机制,以及如何通过JdbcDataSourceClient统一管理不同数据库的连接信息。同时,文档还深入分析了JdbcDialect对不同数据库SQL方言的适配策略,并提供了JDBC连接参数配置的最佳实践和性能优化建议。 + +## 核心组件 + +JDBC连接器由多个核心组件构成,这些组件协同工作以提供稳定可靠的数据库连接服务。主要组件包括JdbcConnector、JdbcDataSourceClient、JdbcDialect、JdbcDataSourceManager和JdbcExecutorClient等。 + +**JdbcConnector** 是所有JDBC数据库连接器的抽象基类,它实现了Connector接口和IJdbcDataSourceInfo接口,为具体的数据库连接器(如MySQL、Oracle等)提供了通用的功能实现。它负责处理数据库的元数据查询,如获取数据库列表、表列表和列信息等。 + +**JdbcDataSourceClient** 是数据源客户端,实现了DataSourceClient接口,负责创建和管理数据源(DataSource)和数据库连接(Connection)。它通过JdbcDataSourceManager来获取数据源实例,并提供了多种方式来获取连接。 + +**JdbcDialect** 是SQL方言的抽象基类,定义了不同数据库在SQL语法上的差异处理策略。它提供了诸如获取列名前缀/后缀、排除系统数据库等功能,确保SQL语句能够在特定数据库上正确执行。 + +**JdbcDataSourceManager** 是连接池管理的核心类,使用HikariCP作为底层连接池实现,负责创建、缓存和管理数据源实例。它通过唯一的键来标识每个数据源,避免了重复创建。 + +**JdbcExecutorClient** 是执行客户端,封装了获取连接和JdbcTemplate的功能,为上层应用提供了便捷的数据库操作接口。 + +**Section sources** +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java#L42-L284) +- [JdbcDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDataSourceClient.java#L32-L89) +- [JdbcDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDialect.java#L33-L76) +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java#L33-L144) +- [JdbcExecutorClient.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcExecutorClient.java#L24-L45) + +## 连接池管理 + +JDBC连接器使用HikariCP作为其连接池实现,通过JdbcDataSourceManager类进行管理。连接池的管理机制确保了数据库连接的高效复用,减少了频繁创建和销毁连接的开销。 + +JdbcDataSourceManager采用单例模式,确保在整个应用生命周期内只有一个实例。它内部维护了一个ConcurrentHashMap,用于缓存已创建的数据源实例。每个数据源实例通过一个唯一的键来标识,该键由数据库URL、用户名和密码的MD5哈希值生成,确保了相同连接配置的数据源不会被重复创建。 + +当需要获取数据源时,JdbcDataSourceManager首先检查缓存中是否存在对应的实例。如果不存在,则创建一个新的HikariConfig配置对象,设置JDBC URL、用户名、密码、驱动类名和最大连接池大小(默认为10),然后创建HikariDataSource实例并将其放入缓存中。这种双重检查的同步机制保证了线程安全。 + +```mermaid +classDiagram +class JdbcDataSourceManager { +-ConcurrentHashMap dataSourceMap ++getInstance() JdbcDataSourceManager ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map) DataSource ++getDataSource(Properties) DataSource ++close() void +} +class BaseJdbcDataSourceInfo { ++getJdbcUrl() String ++getUser() String ++getPassword() String ++getDriverClass() String ++getUniqueKey() String +} +class HikariConfig { ++setJdbcUrl(String) ++setUsername(String) ++setPassword(String) ++setDriverClassName(String) ++setMaximumPoolSize(int) +} +class HikariDataSource { ++getConnection() Connection ++close() void +} +JdbcDataSourceManager --> BaseJdbcDataSourceInfo : "使用" +JdbcDataSourceManager --> HikariConfig : "创建" +HikariConfig --> HikariDataSource : "构建" +JdbcDataSourceManager --> HikariDataSource : "缓存" +``` + +**Diagram sources** +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java#L33-L144) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L34-L198) + +## 连接测试与故障恢复机制 + +JDBC连接器提供了完善的连接测试和故障恢复机制,确保数据库连接的可靠性和稳定性。 + +连接测试功能通过JdbcConnector的testConnect方法实现。该方法接收测试连接请求参数,解析出数据源配置,创建BaseJdbcDataSourceInfo实例,并尝试使用DriverManager.getConnection建立连接。如果连接成功,则返回成功状态;否则捕获SQLException异常,记录错误日志并返回失败状态。此机制允许在配置数据库连接时验证连接的有效性。 + +故障恢复机制主要体现在连接的获取和释放过程中。当通过JdbcDataSourceClient或ConnectionUtils获取连接时,系统会尝试从连接池中获取连接。如果获取失败或连接无效,会抛出DataVinesException异常。在使用完连接后,必须通过JdbcDataSourceUtils.releaseConnection方法显式关闭连接,该方法会安全地处理连接关闭过程,即使发生异常也不会影响主流程。 + +此外,连接池本身也具备一定的故障恢复能力。HikariCP连接池会定期检测连接的健康状况,并自动移除失效的连接。当应用程序请求连接时,连接池会优先提供健康的连接,从而保证了连接的质量。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Connector as "JdbcConnector" +participant DataSourceClient as "JdbcDataSourceClient" +participant DataSourceManager as "JdbcDataSourceManager" +participant Pool as "HikariCP连接池" +Client->>Connector : testConnect(request) +Connector->>Connector : getDatasourceInfo(param) +Connector->>Connector : loadClass() +Connector->>Connector : DriverManager.getConnection() +alt 连接成功 +Connector-->>Client : SUCCESS +else 连接失败 +Connector->>Logger : 记录错误日志 +Connector-->>Client : FAILURE +end +Client->>DataSourceClient : getConnection(configMap) +DataSourceClient->>DataSourceManager : getDataSource(configMap) +DataSourceManager->>Pool : 获取或创建数据源 +Pool-->>DataSourceManager : HikariDataSource +DataSourceManager-->>DataSourceClient : DataSource +DataSourceClient->>DataSource : getConnection() +DataSource-->>Client : Connection +``` + +**Diagram sources** +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java#L196-L212) +- [JdbcDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDataSourceClient.java#L50-L75) +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java#L45-L69) + +## JdbcDataSourceClient统一管理 + +JdbcDataSourceClient是统一管理不同数据库连接信息的核心组件。它实现了DataSourceClient接口,提供了多种方式来获取数据源和数据库连接,包括通过BaseJdbcDataSourceInfo、配置映射(Map)或属性(Properties)等方式。 + +JdbcDataSourceClient通过委托给JdbcDataSourceManager来获取数据源实例。这种设计模式实现了关注点分离,JdbcDataSourceClient负责接口定义和调用,而JdbcDataSourceManager负责具体的连接池管理。当调用getConnection方法时,JdbcDataSourceClient会先获取数据源,然后从数据源中获取连接,并在成功获取后记录日志,便于问题排查。 + +此外,JdbcDataSourceClient还提供了getJdbcTemplate方法,返回一个预配置的JdbcTemplate实例。该实例的fetchSize被设置为500,以优化大数据量查询的性能。这为上层应用提供了更高层次的数据库操作抽象,简化了开发工作。 + +```mermaid +classDiagram +class JdbcDataSourceClient { ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map) DataSource ++getDataSource(Properties) DataSource ++getConnection(BaseJdbcDataSourceInfo) Connection ++getConnection(Map) Connection ++getConnection(Map, Logger) Connection ++getConnection(Properties) Connection ++getJdbcTemplate(BaseJdbcDataSourceInfo) JdbcTemplate +} +class DataSourceClient { +<> ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map) DataSource ++getDataSource(Properties) DataSource ++getConnection(BaseJdbcDataSourceInfo) Connection ++getConnection(Map) Connection ++getConnection(Map, Logger) Connection ++getConnection(Properties) Connection ++getJdbcTemplate(BaseJdbcDataSourceInfo) JdbcTemplate +} +class JdbcDataSourceManager { ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map) DataSource ++getDataSource(Properties) DataSource +} +class JdbcTemplate { ++setFetchSize(int) +} +JdbcDataSourceClient --> DataSourceClient : "实现" +JdbcDataSourceClient --> JdbcDataSourceManager : "委托" +JdbcDataSourceClient --> JdbcTemplate : "创建" +``` + +**Diagram sources** +- [JdbcDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDataSourceClient.java#L32-L89) +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java#L33-L144) + +## JdbcDialect适配策略 + +JdbcDialect是处理不同数据库SQL方言差异的关键组件。它定义了一套抽象方法,允许子类根据具体数据库的特性进行重写,从而实现SQL语句的正确生成和执行。 + +JdbcDialect的适配策略主要包括以下几个方面: + +1. **列名引号处理**:通过getColumnPrefix和getColumnSuffix方法定义列名的前缀和后缀引号。默认实现使用反引号(`),但不同的数据库可能需要使用双引号(")或其他符号。 + +2. **系统数据库排除**:通过getExcludeDatabases方法返回一个包含系统数据库名称的列表。这在获取数据库列表时非常有用,可以避免显示系统内部数据库,提高用户体验。 + +3. **特定SQL脚本生成**:通过getErrorDataScript和getValidateResultDataScript方法生成特定于数据库的查询脚本。例如,根据配置生成查询错误数据或验证结果的SQL语句。 + +4. **分页查询处理**:通过getPageFromResultSet方法处理结果集的分页。虽然默认实现使用了通用的分页逻辑,但可以根据数据库特性进行优化。 + +这种策略使得JDBC连接器能够灵活地适应各种数据库,而无需在核心逻辑中硬编码特定数据库的处理逻辑。 + +```mermaid +classDiagram +class JdbcDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++getErrorDataScript(Map~String,String~) String ++getValidateResultDataScript(Map~String,String~) String ++getPageFromResultSet(Statement, ResultSet, String, int, int) ResultList +} +class Dialect { +<> ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++getErrorDataScript(Map~String,String~) String ++getValidateResultDataScript(Map~String,String~) String ++getPageFromResultSet(Statement, ResultSet, String, int, int) ResultList +} +class MysqlDialect { ++getColumnPrefix() String ++getColumnSuffix() String +} +class OracleDialect { ++getColumnPrefix() String ++getColumnSuffix() String +} +JdbcDialect --> Dialect : "实现" +MysqlDialect --> JdbcDialect : "继承" +OracleDialect --> JdbcDialect : "继承" +``` + +**Diagram sources** +- [JdbcDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDialect.java#L33-L76) +- [Dialect.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\Dialect.java) + +## 连接参数配置最佳实践 + +为了确保JDBC连接的稳定性和安全性,遵循以下连接参数配置最佳实践至关重要: + +1. **连接信息管理**:使用BaseJdbcDataSourceInfo类来封装连接信息。该类提供了统一的接口来获取主机、端口、数据库、用户名、密码等信息,并通过getJdbcUrl方法生成完整的JDBC URL。 + +2. **唯一标识生成**:通过getUniqueKey方法生成数据源的唯一标识。该方法将连接参数转换为字符串,并计算其MD5哈希值,确保了相同配置的数据源具有相同的标识,避免了重复创建。 + +3. **驱动类加载**:在建立连接前,通过loadClass方法显式加载数据库驱动类。这可以提前发现驱动类缺失的问题,避免在运行时才暴露错误。 + +4. **连接参数解析**:使用JdbcUrlParser工具类解析JDBC URL,提取出主机、端口、数据库等信息。这对于处理复杂的连接字符串非常有用。 + +5. **敏感信息处理**:密码等敏感信息应妥善处理,避免在日志中明文显示。系统在记录连接信息时,应考虑对敏感字段进行脱敏。 + +6. **配置验证**:在使用连接参数前,应进行基本的验证,如检查必要字段是否为空,确保JDBC URL格式正确等。 + +**Section sources** +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L34-L198) +- [JdbcUrlParser.java](file://datavines-common\src\main\java\io\datavines\common\utils\JdbcUrlParser.java#L36-L77) +- [ConnectionUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\ConnectionUtils.java#L34-L87) + +## 性能优化建议 + +为了最大化JDBC连接器的性能,建议采取以下优化措施: + +1. **连接池大小调整**:根据应用的并发需求和数据库的承载能力,合理设置连接池大小。默认的10个连接可能不足以应对高并发场景,应根据实际负载进行调整。可以通过修改JdbcDataSourceManager中的setMaximumPoolSize值来调整。 + +2. **连接超时设置**:配置合理的连接超时时间,避免应用程序因等待连接而长时间阻塞。HikariCP提供了connectionTimeout、validationTimeout等参数,应根据网络状况和数据库响应时间进行设置。 + +3. **批量操作优化**:对于大量数据的插入或更新操作,使用批量处理(batch processing)而不是逐条执行。这可以显著减少网络往返次数,提高吞吐量。 + +4. **结果集获取优化**:通过设置合适的fetchSize来优化大结果集的获取。JdbcDataSourceClient中默认设置为500,可以根据查询的数据量和内存使用情况进行调整。 + +5. **连接泄漏预防**:确保每次获取连接后都能正确关闭。使用try-with-resources语句或在finally块中关闭连接,防止连接泄漏导致连接池耗尽。 + +6. **监控和调优**:启用连接池的监控功能,定期检查连接池的状态,如活跃连接数、空闲连接数、等待线程数等。根据监控数据进行针对性的调优。 + +7. **SQL语句优化**:编写高效的SQL语句,避免全表扫描,合理使用索引。对于复杂的查询,考虑使用执行计划分析工具进行优化。 + +**Section sources** +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java#L60-L61) +- [JdbcDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDataSourceClient.java#L85-L86) +- [JdbcExecutorClient.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcExecutorClient.java#L41-L42) + +## 结论 +JDBC连接器作为DataVines平台与各种关系型数据库交互的桥梁,其设计充分考虑了可扩展性、稳定性和性能。通过连接池管理、统一的连接信息管理、SQL方言适配等机制,它为上层应用提供了简单而强大的数据库访问能力。理解其内部工作原理和最佳实践,有助于开发者更好地利用这一组件,构建高效、可靠的数据库应用。未来,可以进一步增强连接池的动态调整能力,引入更智能的故障恢复策略,以及支持更多的数据库类型,以满足不断变化的业务需求。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/MySQL\350\277\236\346\216\245\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/MySQL\350\277\236\346\216\245\345\231\250.md" new file mode 100644 index 00000000..db6b492e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/MySQL\350\277\236\346\216\245\345\231\250.md" @@ -0,0 +1,309 @@ +# MySQL连接器 + + +**本文档中引用的文件** +- [MysqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDataSourceInfo.java) +- [MysqlDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDialect.java) +- [MysqlConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlConfigBuilder.java) +- [MysqlExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlExecutor.java) +- [MysqlConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlConnector.java) +- [JdbcDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDialect.java) +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java) +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) + + +## 目录 +1. [简介](#简介) +2. [MySQL连接器架构](#mysql连接器架构) +3. [MysqlDataSourceInfo实现](#mysqldatasourceinfo实现) +4. [MysqlDialect适配策略](#mysqldialect适配策略) +5. [性能优化特性](#性能优化特性) +6. [连接参数配置最佳实践](#连接参数配置最佳实践) +7. [常见问题解决方案](#常见问题解决方案) +8. [结论](#结论) + +## 简介 + +MySQL连接器是DataVines数据质量平台中用于连接和操作MySQL数据库的核心组件。该连接器基于JDBC标准实现,提供了对MySQL数据库的全面支持,包括连接管理、元数据获取、SQL执行和数据质量验证等功能。本文档详细分析MySQL连接器的实现细节,重点关注其对MySQL特有功能的支持、SQL语法适配策略以及性能优化机制。 + +MySQL连接器的设计遵循了模块化和可扩展的原则,通过继承和实现基类与接口来提供特定于MySQL的功能。连接器的主要功能包括:建立和管理数据库连接、获取数据库元数据(如数据库列表、表结构、列信息等)、执行SQL查询和更新操作,以及支持数据质量检查和错误数据存储。 + +**本节内容未分析具体源文件,因此不提供来源信息** + +## MySQL连接器架构 + +MySQL连接器的整体架构基于JDBC插件体系,通过继承通用JDBC组件并实现MySQL特定功能来完成。连接器的核心组件包括MysqlDataSourceInfo、MysqlDialect、MysqlExecutor和MysqlConnector,它们分别负责连接信息管理、SQL语法适配、执行逻辑和连接操作。 + +```mermaid +classDiagram +class MysqlDataSourceInfo { ++getAddress() String ++getDriverClass() String ++getType() String ++getSeparator() String +} +class MysqlDialect { ++getDriver() String ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++quoteIdentifier(String) String ++getQuoteIdentifier() String +} +class MysqlExecutor { ++MysqlExecutor(DataSourceClient) ++getDatasourceInfo(Map) BaseJdbcDataSourceInfo +} +class MysqlConnector { ++MysqlConnector(DataSourceClient) ++getDatasourceInfo(Map) BaseJdbcDataSourceInfo ++getMetadataDatabases(Connection) ResultSet +} +class MysqlConfigBuilder { ++buildErrorDataStorage(boolean) String ++getPropertiesInput(boolean) InputParam ++getDatabaseInput(boolean) InputParam ++getErrorDataStorageDatabaseInput(boolean) InputParam +} +MysqlDataSourceInfo --|> BaseJdbcDataSourceInfo : 继承 +MysqlDialect --|> JdbcDialect : 继承 +MysqlExecutor --|> BaseJdbcExecutor : 继承 +MysqlConnector --|> JdbcConnector : 继承 +MysqlConfigBuilder --|> JdbcConfigBuilder : 继承 +MysqlExecutor --> MysqlDataSourceInfo : 使用 +MysqlConnector --> MysqlDataSourceInfo : 使用 +MysqlConfigBuilder --> MysqlDataSourceInfo : 配置 +``` + +**图示来源** +- [MysqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDataSourceInfo.java) +- [MysqlDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDialect.java) +- [MysqlExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlExecutor.java) +- [MysqlConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlConnector.java) +- [MysqlConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlConfigBuilder.java) + +**本节来源** +- [MysqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDataSourceInfo.java) +- [MysqlDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDialect.java) +- [MysqlExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlExecutor.java) +- [MysqlConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlConnector.java) +- [MysqlConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlConfigBuilder.java) + +## MysqlDataSourceInfo实现 + +MysqlDataSourceInfo类负责处理MySQL数据库的连接信息和特定参数。作为BaseJdbcDataSourceInfo的子类,它实现了MySQL特有的连接地址生成、驱动类指定和类型标识功能。 + +该类的核心功能包括: +1. 连接地址生成:通过getAddress()方法生成标准的JDBC连接URL,格式为"jdbc:mysql://host:port" +2. 驱动类指定:返回MySQL Connector/J的驱动类名"com.mysql.cj.jdbc.Driver" +3. 类型标识:返回数据源类型为"mysql" +4. 参数分隔符:使用"?"作为连接参数的分隔符 + +MysqlDataSourceInfo继承了基类的参数解析功能,能够处理主机、端口、用户名、密码等基本连接参数,并通过父类的机制生成完整的JDBC连接URL。这种设计使得MySQL特定的连接逻辑与通用的JDBC连接管理分离,提高了代码的可维护性和可扩展性。 + +```mermaid +classDiagram +class BaseJdbcDataSourceInfo { ++getHost() String ++getPort() int ++getUser() String ++getPassword() String ++getDatabase() String ++getJdbcUrl() String ++getUniqueKey() String ++loadClass() void +} +class MysqlDataSourceInfo { ++getAddress() String ++getDriverClass() String ++getType() String ++getSeparator() String +} +MysqlDataSourceInfo --|> BaseJdbcDataSourceInfo : 继承 +note right of MysqlDataSourceInfo +实现MySQL特有功能: +- getAddress() : 生成jdbc : mysql : //host : port +- getDriverClass() : 返回MySQL驱动类 +- getType() : 返回数据源类型 +- getSeparator() : 返回参数分隔符 +end note +``` + +**图示来源** +- [MysqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) + +**本节来源** +- [MysqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDataSourceInfo.java) + +## MysqlDialect适配策略 + +MysqlDialect类负责处理MySQL特有的SQL语法和函数适配。作为JdbcDialect的子类,它重写了多个方法以支持MySQL的特定行为和功能。 + +主要适配策略包括: +1. 驱动类指定:返回MySQL Connector/J的驱动类名"com.mysql.cj.jdbc.Driver" +2. 标识符引用:使用反引号(`)作为标识符的引用符号,这是MySQL的标准做法 +3. 错误数据存储支持:支持将错误数据存储到同一数据源中 +4. 无效项输出:允许将无效项输出到自身 + +MysqlDialect继承了JdbcDialect的通用SQL处理功能,同时通过重写方法来适应MySQL的特定需求。例如,quoteIdentifier方法使用反引号而不是标准的双引号来引用标识符,这符合MySQL的语法规范。这种设计使得SQL语句在不同数据库之间的移植更加容易,同时保持了对特定数据库特性的支持。 + +```mermaid +classDiagram +class JdbcDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++getErrorDataScript(Map) String ++getValidateResultDataScript(Map) String ++getPageFromResultSet(Statement, ResultSet, String, int, int) ResultList +} +class MysqlDialect { ++getDriver() String ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++quoteIdentifier(String) String ++getQuoteIdentifier() String +} +MysqlDialect --|> JdbcDialect : 继承 +note right of MysqlDialect +重写方法以适应MySQL特性: +- getDriver() : 返回MySQL驱动 +- quoteIdentifier() : 使用反引号引用 +- supportToBeErrorDataStorage() : 支持错误数据存储 +- invalidateItemCanOutputToSelf() : 允许无效项输出到自身 +end note +``` + +**图示来源** +- [MysqlDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDialect.java) +- [JdbcDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcDialect.java) + +**本节来源** +- [MysqlDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDialect.java) + +## 性能优化特性 + +MySQL连接器在设计时考虑了多种性能优化策略,以提高数据处理效率和系统响应速度。这些优化特性主要体现在连接管理、查询执行和数据处理等方面。 + +连接管理方面,连接器利用JdbcExecutorClientManager的单例模式和ConcurrentHashMap来缓存和复用数据库连接,避免了频繁创建和销毁连接的开销。每个唯一的数据源配置都有一个对应的JdbcExecutorClient实例,通过getUniqueKey()方法生成的键值进行标识和查找。 + +查询执行方面,连接器在JdbcTemplate中设置了合理的fetchSize(500),这可以减少网络往返次数,提高大数据量查询的效率。同时,提供了多种查询方法(queryForPage、queryForOne、queryForList)以适应不同的使用场景,避免不必要的数据加载。 + +数据处理方面,连接器通过流式处理和分页查询来支持大数据集的操作。例如,getMetadataDatabases方法使用"show databases"语句直接获取数据库列表,而不是通过标准的JDBC元数据方法,这在某些情况下可以提高性能。 + +```mermaid +flowchart TD +Start([开始]) --> ConnectionManagement["连接管理"] +ConnectionManagement --> ConnectionPool["连接池管理"] +ConnectionPool --> ClientManager["JdbcExecutorClientManager"] +ClientManager --> ConcurrentHashMap["ConcurrentHashMap缓存"] +ConcurrentHashMap --> UniqueKey["基于getUniqueKey()的键值"] +Start --> QueryExecution["查询执行"] +QueryExecution --> JdbcTemplate["JdbcTemplate配置"] +JdbcTemplate --> FetchSize["设置fetchSize=500"] +FetchSize --> NetworkOptimization["减少网络往返"] +Start --> DataProcessing["数据处理"] +DataProcessing --> Streaming["流式处理"] +Streaming --> Pagination["分页查询"] +Pagination --> EfficientQuery["高效查询方法"] +EfficientQuery --> ShowDatabases["使用show databases"] +ConnectionPool --> Performance["性能优化"] +QueryExecution --> Performance +DataProcessing --> Performance +Performance --> End([结束]) +``` + +**图示来源** +- [JdbcExecutorClientManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcExecutorClientManager.java) +- [JdbcExecutorClient.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcExecutorClient.java) +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java) +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java) + +**本节来源** +- [JdbcExecutorClientManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcExecutorClientManager.java) +- [JdbcExecutorClient.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcExecutorClient.java) +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java) +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java) + +## 连接参数配置最佳实践 + +MySQL连接器通过MysqlConfigBuilder类提供了连接参数的配置构建功能。该类继承自JdbcConfigBuilder,重写了相关方法以支持MySQL特有的配置需求。 + +在连接参数配置方面,最佳实践包括: +1. 必需参数:确保正确配置主机、端口和数据库名称等基本连接参数 +2. 字符编码:设置useUnicode=true&characterEncoding=UTF-8以支持中文字符 +3. SSL配置:根据安全需求设置useSSL参数,生产环境建议启用SSL +4. 时区设置:配置serverTimezone参数以避免时区相关的问题 +5. 连接属性:合理设置其他连接属性以优化性能和稳定性 + +MysqlConfigBuilder的getPropertiesInput方法提供了默认的连接参数配置,包括字符编码、SSL设置、时区和信息模式访问等。这些默认配置考虑了大多数使用场景的需求,开发者可以根据具体环境进行调整。 + +```mermaid +flowchart TD +Start([配置开始]) --> RequiredParams["必需参数"] +RequiredParams --> Host["主机"] +RequiredParams --> Port["端口"] +RequiredParams --> Database["数据库"] +Start --> CharacterEncoding["字符编码"] +CharacterEncoding --> UseUnicode["useUnicode=true"] +CharacterEncoding --> CharacterEncodingUTF8["characterEncoding=UTF-8"] +Start --> SSLConfiguration["SSL配置"] +SSLConfiguration --> UseSSL["useSSL=false/true"] +SSLConfiguration --> AllowPublicKeyRetrieval["allowPublicKeyRetrieval=true"] +Start --> TimezoneSetting["时区设置"] +TimezoneSetting --> ServerTimezone["serverTimezone=Asia/Shanghai"] +Start --> ConnectionProperties["连接属性"] +ConnectionProperties --> UseInformationSchema["useInformationSchema=true"] +ConnectionProperties --> OtherProperties["其他属性"] +RequiredParams --> BestPractice["最佳实践"] +CharacterEncoding --> BestPractice +SSLConfiguration --> BestPractice +TimezoneSetting --> BestPractice +ConnectionProperties --> BestPractice +BestPractice --> End([配置完成]) +``` + +**图示来源** +- [MysqlConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlConfigBuilder.java) +- [JdbcConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConfigBuilder.java) + +**本节来源** +- [MysqlConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlConfigBuilder.java) + +## 常见问题解决方案 + +在使用MySQL连接器时,可能会遇到一些常见问题。以下是这些问题的解决方案: + +1. **连接失败问题**:检查主机、端口、用户名和密码是否正确,确保MySQL服务器正在运行且网络可达。如果使用SSL连接,确保SSL配置正确。 + +2. **字符编码问题**:如果出现中文乱码,确保在连接参数中设置了useUnicode=true&characterEncoding=UTF-8。 + +3. **时区问题**:如果时间数据出现偏差,检查serverTimezone参数是否正确设置为目标时区。 + +4. **权限问题**:确保连接用户具有足够的权限访问目标数据库和表。 + +5. **性能问题**:对于大数据量查询,考虑调整fetchSize参数或使用分页查询。 + +6. **驱动类问题**:确保classpath中包含正确版本的MySQL Connector/J驱动。 + +7. **元数据获取问题**:如果无法获取表或列信息,检查用户是否具有访问information_schema的权限。 + +通过合理配置连接参数和遵循最佳实践,可以有效避免大多数常见问题。对于复杂问题,建议查看详细的错误日志以获取更多信息。 + +**本节来源** +- [MysqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDataSourceInfo.java) +- [MysqlDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlDialect.java) +- [MysqlConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlConfigBuilder.java) + +## 结论 + +MySQL连接器通过继承和扩展通用JDBC组件,实现了对MySQL数据库的全面支持。MysqlDataSourceInfo类处理MySQL特有的连接参数和URL生成,MysqlDialect类适配MySQL的SQL语法和函数特性,而MysqlExecutor和MysqlConnector类则提供了执行逻辑和连接操作功能。 + +连接器的设计体现了良好的面向对象原则和模块化思想,通过继承基类和实现接口来提供特定功能,同时保持了代码的可维护性和可扩展性。性能优化方面,连接器通过连接池管理、合理的fetchSize设置和高效的查询方法来提高数据处理效率。 + +在实际使用中,应遵循连接参数配置的最佳实践,合理设置字符编码、SSL和时区等参数,以确保连接的稳定性和数据的正确性。对于常见问题,可以通过检查配置、查看日志和调整参数来解决。 + +总体而言,MySQL连接器是一个功能完整、性能优良的数据库连接组件,为DataVines平台提供了可靠的MySQL数据库访问能力。 + +**本节内容未分析具体源文件,因此不提供来源信息** \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/Oracle\350\277\236\346\216\245\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/Oracle\350\277\236\346\216\245\345\231\250.md" new file mode 100644 index 00000000..68927bb3 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/Oracle\350\277\236\346\216\245\345\231\250.md" @@ -0,0 +1,291 @@ +# Oracle连接器 + + +**本文档引用的文件** +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [OracleDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDialect.java) +- [OracleConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConfigBuilder.java) +- [OracleExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleExecutor.java) +- [OracleParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleParameterConverter.java) +- [OracleTypeConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleTypeConverter.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +Oracle连接器是DataVines平台中用于连接和操作Oracle数据库的核心组件。该连接器实现了Oracle数据库特有的连接参数处理、SQL语法支持以及性能优化特性。本文档详细描述了Oracle连接器的实现机制,包括OracleDataSourceInfo对Oracle连接参数的处理、OracleDialect对Oracle SQL语法的支持,以及连接器的性能优化特性。 + +## 项目结构 +Oracle连接器位于`datavines-connector-plugins`模块下的`datavines-connector-oracle`子模块中。该结构遵循DataVines插件化架构设计,将Oracle数据库的连接功能封装为独立的插件。 + +```mermaid +graph TD +A[datavines-connector] --> B[datavines-connector-plugins] +B --> C[datavines-connector-oracle] +C --> D[src/main/java/io/datavines/connector/plugin] +C --> E[src/main/resources/META-INF/plugins] +D --> F[OracleConnector.java] +D --> G[OracleDataSourceInfo.java] +D --> H[OracleDialect.java] +D --> I[OracleConfigBuilder.java] +D --> J[OracleExecutor.java] +D --> K[OracleParameterConverter.java] +D --> L[OracleTypeConverter.java] +E --> M[io.datavines.connector.api.ConnectorFactory] +``` + +**图示来源** +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [OracleDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDialect.java) + +**章节来源** +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [OracleDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDialect.java) + +## 核心组件 +Oracle连接器的核心组件包括OracleConnector、OracleDataSourceInfo、OracleDialect等类,它们共同实现了Oracle数据库的连接、配置和操作功能。这些组件通过继承和扩展通用JDBC组件,实现了Oracle数据库特有的功能。 + +**章节来源** +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [OracleDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDialect.java) + +## 架构概述 +Oracle连接器采用分层架构设计,基于DataVines的插件化架构,通过继承通用JDBC组件来实现Oracle数据库的特定功能。该架构遵循面向接口编程原则,通过工厂模式创建具体的连接器实例。 + +```mermaid +classDiagram +class OracleConnectorFactory { ++getConnectorParameterConverter() ParameterConverter ++getDialect() Dialect ++getConnector() Connector ++getExecutor() Executor ++getConfigBuilder() ConfigBuilder ++getTypeConverter() TypeConverter ++getMetricScript() MetricScript +} +class OracleConnector { ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo ++getMetadataColumns(DatabaseMetaData, String, String, String, String) ResultSet ++getMetadataTables(DatabaseMetaData, String, String) ResultSet ++getPrimaryKeys(DatabaseMetaData, String, String, String) ResultSet ++getMetadataDatabases(Connection) ResultSet +} +class OracleDataSourceInfo { ++getAddress() String ++getDriverClass() String ++getType() String ++getValidationQuery() String ++getJdbcUrl() String ++appendSid(StringBuilder) void +} +class OracleDialect { ++getDriver() String ++invalidateItemCanOutputToSelf() boolean ++getFullQualifiedTableName(String, String, String, boolean) String +} +class OracleConfigBuilder { ++build(boolean) String ++getSID(boolean) InputParam +} +class OracleExecutor { ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo +} +OracleConnectorFactory --> OracleParameterConverter : "创建" +OracleConnectorFactory --> OracleDialect : "创建" +OracleConnectorFactory --> OracleConnector : "创建" +OracleConnectorFactory --> OracleExecutor : "创建" +OracleConnectorFactory --> OracleConfigBuilder : "创建" +OracleConnectorFactory --> OracleTypeConverter : "创建" +OracleConnectorFactory --> OracleMetricScript : "创建" +OracleConnector --> OracleDataSourceInfo : "使用" +OracleExecutor --> OracleDataSourceInfo : "使用" +OracleDialect --> JdbcDialect : "继承" +OracleConnector --> JdbcConnector : "继承" +OracleDataSourceInfo --> BaseJdbcDataSourceInfo : "继承" +``` + +**图示来源** +- [OracleConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnectorFactory.java) +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [OracleDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDialect.java) +- [OracleConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConfigBuilder.java) +- [OracleExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleExecutor.java) + +## 详细组件分析 + +### OracleDataSourceInfo分析 +OracleDataSourceInfo类负责处理Oracle数据库特有的连接参数,包括服务名/SID的处理。该类继承自BaseJdbcDataSourceInfo,重写了相关方法以适应Oracle数据库的连接要求。 + +```mermaid +flowchart TD +Start([开始]) --> GetAddress["获取基础地址 jdbc:oracle:thin:@//host:port"] +GetAddress --> CheckSID["检查SID参数是否存在"] +CheckSID --> |存在| AppendSID["在地址后追加/SID"] +CheckSID --> |不存在| UseAddress["直接使用基础地址"] +AppendSID --> BuildURL["构建完整JDBC URL"] +UseAddress --> BuildURL +BuildURL --> AddProperties["添加其他连接属性"] +AddProperties --> ReturnURL["返回完整JDBC连接字符串"] +ReturnURL --> End([结束]) +``` + +**图示来源** +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +**章节来源** +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +### OracleDialect分析 +OracleDialect类实现了Oracle数据库特有的SQL语法支持。该类继承自JdbcDialect,重写了相关方法以适应Oracle数据库的SQL语法特点。 + +```mermaid +classDiagram +class OracleDialect { ++getDriver() String ++invalidateItemCanOutputToSelf() boolean ++getFullQualifiedTableName(String, String, String, boolean) String +} +class JdbcDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++getErrorDataScript(Map~String,String~) String ++getValidateResultDataScript(Map~String,String~) String ++getPageFromResultSet(Statement, ResultSet, String, int, int) ResultList +} +OracleDialect --> JdbcDialect : "继承" +note right of OracleDialect +重写getFullQualifiedTableName方法: +- 不使用catalog作为数据库名 +- schema和table名使用大写 +- 支持Oracle特有的命名规则 +end note +``` + +**图示来源** +- [OracleDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDialect.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) + +**章节来源** +- [OracleDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDialect.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) + +### Oracle连接参数配置分析 +Oracle连接器通过OracleConfigBuilder类构建连接参数配置界面,支持用户输入Oracle特有的连接参数。 + +```mermaid +flowchart TD +Start([配置构建开始]) --> AddHost["添加主机输入项"] +AddHost --> AddPort["添加端口输入项"] +AddPort --> AddSID["添加SID输入项"] +AddSID --> AddUser["添加用户名输入项"] +AddUser --> AddPassword["添加密码输入项"] +AddPassword --> AddProperties["添加连接属性输入项"] +AddProperties --> AddOthers["添加其他参数"] +AddOthers --> Serialize["序列化为JSON格式"] +Serialize --> ReturnConfig["返回配置JSON字符串"] +ReturnConfig --> End([配置构建结束]) +style AddSID fill:#f9f,stroke:#333 +note right of AddSID +SID参数为必填项 +提示信息支持中英文 +用于构建Oracle连接字符串 +end note +``` + +**图示来源** +- [OracleConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConfigBuilder.java) +- [OracleParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleParameterConverter.java) + +**章节来源** +- [OracleConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConfigBuilder.java) +- [OracleParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleParameterConverter.java) + +## 依赖分析 +Oracle连接器的依赖关系体现了其插件化架构特点,通过继承和组合的方式复用通用JDBC组件的功能,同时实现Oracle数据库的特定功能。 + +```mermaid +graph TD +A[OracleConnectorFactory] --> B[OracleParameterConverter] +A --> C[OracleDialect] +A --> D[OracleConnector] +A --> E[OracleExecutor] +A --> F[OracleConfigBuilder] +A --> G[OracleTypeConverter] +A --> H[OracleMetricScript] +D --> I[OracleDataSourceInfo] +E --> I +I --> J[BaseJdbcDataSourceInfo] +C --> K[JdbcDialect] +D --> L[JdbcConnector] +M[Oracle连接器] --> N[Oracle JDBC驱动] +N --> O[Oracle数据库] +style A fill:#ff9999,stroke:#333 +style D fill:#99ff99,stroke:#333 +style I fill:#9999ff,stroke:#333 +style J fill:#ffff99,stroke:#333 +note right of A +工厂类负责创建所有Oracle相关组件 +end note +note right of D +连接器实现Oracle数据库操作 +end note +note right of I +数据源信息处理Oracle连接参数 +end note +note right of J +基础JDBC数据源信息类 +end note +``` + +**图示来源** +- [OracleConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnectorFactory.java) +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +**章节来源** +- [OracleConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnectorFactory.java) +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +## 性能考虑 +Oracle连接器在设计时考虑了性能优化,特别是在连接管理和SQL执行方面。通过连接池管理和批量操作支持,提高了与Oracle数据库交互的效率。 + +**章节来源** +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [OracleExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleExecutor.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +## 故障排除指南 +Oracle连接器的故障排除主要集中在连接配置和驱动依赖方面。确保Oracle JDBC驱动正确配置是成功连接的关键。 + +**章节来源** +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) + +## 结论 +Oracle连接器通过继承和扩展通用JDBC组件,实现了对Oracle数据库的完整支持。该连接器正确处理了Oracle特有的连接参数(如SID),支持Oracle SQL语法,并提供了良好的性能特性。通过插件化架构,Oracle连接器能够无缝集成到DataVines平台中,为用户提供可靠的Oracle数据库连接服务。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/PostgreSQL\350\277\236\346\216\245\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/PostgreSQL\350\277\236\346\216\245\345\231\250.md" new file mode 100644 index 00000000..22e9b60c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/PostgreSQL\350\277\236\346\216\245\345\231\250.md" @@ -0,0 +1,319 @@ +# PostgreSQL连接器 + + +**本文档引用的文件** +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) +- [PostgreSqlExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlExecutor.java) +- [PostgreSqlConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConfigBuilder.java) +- [PostgreSqlTypeConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlTypeConverter.java) +- [PostgreSqlParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlParameterConverter.java) +- [PostgreSqlMetricScript.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlMetricScript.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +PostgreSQL连接器是DataVines数据质量平台中的一个关键组件,用于与PostgreSQL数据库进行交互。该连接器实现了针对PostgreSQL数据库的特定功能,包括连接参数处理、SQL语法支持、数据类型转换等。本文档详细介绍了PostgreSQL连接器的实现细节,包括其核心组件、架构设计、性能优化特性以及配置最佳实践。 + +## 项目结构 +PostgreSQL连接器位于`datavines-connector-plugins`模块下的`datavines-connector-postgresql`子模块中。该结构遵循DataVines的插件化设计模式,允许灵活地添加和管理不同的数据库连接器。 + +```mermaid +graph TD +subgraph "datavines-connector-plugins" +postgresql[datavines-connector-postgresql] +mysql[datavines-connector-mysql] +oracle[datavines-connector-oracle] +sqlserver[datavines-connector-sqlserver] +clickhouse[datavines-connector-clickhouse] +hive[datavines-connector-hive] +mongodb[datavines-connector-mongodb] +end +postgresql --> jdbc[datavines-connector-jdbc] +jdbc --> connector-api[datavines-connector-api] +connector-api --> common[datavines-common] +``` + +**图源** +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/pom.xml) + +**本节来源** +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/pom.xml) + +## 核心组件 +PostgreSQL连接器的核心组件包括`PostgreSqlConnector`、`PostgreSqlDataSourceInfo`、`PostgreSqlDialect`和`PostgreSqlExecutor`等类。这些组件共同协作,实现了与PostgreSQL数据库的连接、查询和数据操作功能。 + +**本节来源** +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) +- [PostgreSqlExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlExecutor.java) + +## 架构概述 +PostgreSQL连接器的架构基于DataVines的通用JDBC连接器架构,通过继承和扩展基类来实现PostgreSQL特定的功能。这种设计模式允许代码重用,同时保持了针对特定数据库的定制化能力。 + +```mermaid +classDiagram +class PostgreSqlConnector { ++getDatasourceInfo(param) BaseJdbcDataSourceInfo ++getMetadataDatabases(connection) ResultSet ++getMetadataTables(metaData, catalog, schema) ResultSet +} +class PostgreSqlDataSourceInfo { ++getAddress() String ++getDriverClass() String ++getType() String ++getSeparator() String ++filterProperties(other) String ++getValidationQuery() String +} +class PostgreSqlDialect { ++getDriver() String +} +class PostgreSqlExecutor { ++getDatasourceInfo(param) BaseJdbcDataSourceInfo +} +class PostgreSqlConfigBuilder { ++getSchemaInput(isEn) InputParam +} +class PostgreSqlTypeConverter { ++convert(originType) DataType ++convertToOriginType(dataType) String +} +class PostgreSqlParameterConverter { ++getUrl(parameter) String +} +class PostgreSqlMetricScript { ++maxLengthActualValue(uniqueKey) String ++minLengthActualValue(uniqueKey) String ++columnLengthCompare() String ++columnMatchRegex() String ++columnNotMatchRegex() String ++avgLengthActualValue(uniqueKey) String ++histogramActualValue(uniqueKey, where) String +} +PostgreSqlConnector --> PostgreSqlDataSourceInfo : "使用" +PostgreSqlConnector --> PostgreSqlDialect : "依赖" +PostgreSqlExecutor --> PostgreSqlDataSourceInfo : "使用" +PostgreSqlConnector --> PostgreSqlExecutor : "依赖" +PostgreSqlConnector --> PostgreSqlConfigBuilder : "依赖" +PostgreSqlConnector --> PostgreSqlTypeConverter : "依赖" +PostgreSqlConnector --> PostgreSqlParameterConverter : "依赖" +PostgreSqlConnector --> PostgreSqlMetricScript : "依赖" +PostgreSqlTypeConverter --> DataType : "转换" +``` + +**图源** +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) +- [PostgreSqlExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlExecutor.java) +- [PostgreSqlConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConfigBuilder.java) +- [PostgreSqlTypeConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlTypeConverter.java) +- [PostgreSqlParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlParameterConverter.java) +- [PostgreSqlMetricScript.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlMetricScript.java) + +## 详细组件分析 + +### PostgreSQL连接器分析 +PostgreSQL连接器通过继承`JdbcConnector`基类,实现了针对PostgreSQL数据库的特定功能。它负责管理与PostgreSQL数据库的连接,并提供元数据查询功能。 + +#### 对象关系图 +```mermaid +classDiagram +JdbcConnector <|-- PostgreSqlConnector +BaseJdbcDataSourceInfo <|-- PostgreSqlDataSourceInfo +JdbcDialect <|-- PostgreSqlDialect +BaseJdbcExecutor <|-- PostgreSqlExecutor +PostgreSqlConnector --> PostgreSqlDataSourceInfo : "创建" +PostgreSqlConnector --> PostgreSqlDialect : "使用" +PostgreSqlConnector --> PostgreSqlExecutor : "使用" +PostgreSqlConnector --> PostgreSqlConfigBuilder : "使用" +PostgreSqlConnector --> PostgreSqlTypeConverter : "使用" +PostgreSqlConnector --> PostgreSqlParameterConverter : "使用" +PostgreSqlConnector --> PostgreSqlMetricScript : "使用" +``` + +**图源** +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +#### 连接器工作流程 +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Connector as "PostgreSqlConnector" +participant DataSource as "DataSourceClient" +participant Connection as "数据库连接" +Client->>Connector : getDatabases(param) +Connector->>DataSource : getConnection() +DataSource->>Connection : 创建连接 +Connection-->>DataSource : 返回连接 +DataSource-->>Connector : 返回连接 +Connector->>Connection : getMetadataDatabases() +Connection-->>Connector : 返回数据库列表 +Connector-->>Client : 返回结果 +Client->>Connector : getTables(param) +Connector->>DataSource : getConnection() +DataSource->>Connection : 创建连接 +Connection-->>DataSource : 返回连接 +DataSource-->>Connector : 返回连接 +Connector->>Connection : getMetadataTables() +Connection-->>Connector : 返回表列表 +Connector-->>Client : 返回结果 +``` + +**图源** +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +**本节来源** +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +### PostgreSqlDataSourceInfo分析 +`PostgreSqlDataSourceInfo`类负责处理PostgreSQL特有的连接参数。它继承自`BaseJdbcDataSourceInfo`,并重写了相关方法以适应PostgreSQL的连接要求。 + +#### 数据源信息处理流程 +```mermaid +flowchart TD +Start([开始]) --> GetHost["获取主机地址"] +GetHost --> GetPort["获取端口号"] +GetPort --> BuildAddress["构建JDBC地址"] +BuildAddress --> AddDatabase["添加数据库名"] +AddDatabase --> AddProperties["添加连接属性"] +AddProperties --> FilterSensitive["过滤敏感参数"] +FilterSensitive --> ReturnUrl["返回完整JDBC URL"] +ReturnUrl --> End([结束]) +FilterSensitive --> |包含autoDeserialize| LogWarning["记录警告日志"] +LogWarning --> RemoveSensitive["移除敏感参数"] +RemoveSensitive --> AddProperties +``` + +**图源** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +**本节来源** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +### PostgreSqlDialect分析 +`PostgreSqlDialect`类实现了PostgreSQL特定的SQL语法支持。它继承自`JdbcDialect`基类,并提供了PostgreSQL驱动程序的类名。 + +#### SQL语法支持特性 +```mermaid +erDiagram +METRIC_SCRIPT { +string maxLengthActualValue +string minLengthActualValue +string columnLengthCompare +string columnMatchRegex +string columnNotMatchRegex +string avgLengthActualValue +string histogramActualValue +} +METRIC_SCRIPT ||--o{ POSTGRESQL_METRIC_SCRIPT : "实现" +class PostgreSqlMetricScript { ++maxLengthActualValue(uniqueKey) String ++minLengthActualValue(uniqueKey) String ++columnLengthCompare() String ++columnMatchRegex() String ++columnNotMatchRegex() String ++avgLengthActualValue(uniqueKey) String ++histogramActualValue(uniqueKey, where) String +} +``` + +**图源** +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [PostgreSqlMetricScript.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlMetricScript.java) + +**本节来源** +- [PostgreSqlDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [PostgreSqlMetricScript.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlMetricScript.java) + +## 依赖分析 +PostgreSQL连接器的依赖关系清晰地展示了其模块化设计。它依赖于通用的JDBC连接器组件,同时提供了PostgreSQL特定的实现。 + +```mermaid +graph TD +postgresql[PostgreSQL连接器] --> jdbc[JDBC连接器] +jdbc --> connector-api[连接器API] +connector-api --> common[通用组件] +common --> utils[工具类] +common --> config[配置管理] +postgresql --> postgresql-driver[PostgreSQL JDBC驱动] +jdbc --> hikari[HikariCP连接池] +connector-api --> spi[SPI机制] +``` + +**图源** +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/pom.xml) + +**本节来源** +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/pom.xml) + +## 性能考虑 +PostgreSQL连接器在设计时考虑了性能优化,特别是在处理大数据量查询和连接管理方面。 + +### 连接池配置 +PostgreSQL连接器利用HikariCP连接池来管理数据库连接,这有助于提高性能和资源利用率。连接池配置包括最大连接数、最小连接数、连接超时等参数,可以根据实际需求进行调整。 + +### 批量操作支持 +虽然当前代码中没有直接体现,但基于JDBC的标准实现,PostgreSQL连接器支持批量插入、更新和删除操作。这些操作可以显著提高数据处理效率,特别是在处理大量数据时。 + +### 查询优化 +PostgreSQL连接器通过使用预编译语句和参数化查询来防止SQL注入,并提高查询执行效率。此外,连接器还支持分页查询,可以有效处理大规模数据集。 + +**本节来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +## 故障排除指南 +在使用PostgreSQL连接器时,可能会遇到一些常见问题。以下是一些解决方案和最佳实践。 + +### 连接问题 +如果无法连接到PostgreSQL数据库,请检查以下几点: +- 确认主机地址、端口号和数据库名称是否正确 +- 检查用户名和密码是否正确 +- 确认PostgreSQL服务器是否正在运行 +- 检查防火墙设置,确保端口未被阻止 +- 确认PostgreSQL的`pg_hba.conf`文件中是否允许来自客户端的连接 + +### SSL连接配置 +PostgreSQL支持SSL连接,可以在连接字符串中添加SSL相关参数: +``` +jdbc:postgresql://host:port/database?ssl=true&sslmode=require +``` + +### 性能问题 +如果遇到性能问题,可以考虑以下优化措施: +- 调整连接池大小,根据负载情况设置合适的最大和最小连接数 +- 使用索引优化查询性能 +- 避免在查询中使用`SELECT *`,只选择需要的列 +- 使用分页查询处理大规模数据集 + +**本节来源** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [PostgreSqlParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlParameterConverter.java) + +## 结论 +PostgreSQL连接器是DataVines平台中一个重要的组件,它提供了与PostgreSQL数据库的高效、安全的连接和交互能力。通过继承和扩展通用JDBC连接器架构,PostgreSQL连接器实现了针对PostgreSQL特定功能的支持,包括连接参数处理、SQL语法支持、数据类型转换等。该连接器的设计体现了模块化和可扩展性,为未来的功能增强和维护提供了良好的基础。通过合理配置和使用,PostgreSQL连接器可以帮助用户有效地管理和监控PostgreSQL数据库的数据质量。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/datavines-connector\346\250\241\345\235\227.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/datavines-connector\346\250\241\345\235\227.md" new file mode 100644 index 00000000..0b01b8d9 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/datavines-connector\346\250\241\345\235\227.md" @@ -0,0 +1,645 @@ +# datavines-connector模块 + + +**本文档引用的文件** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [ConfigBuilder.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) +- [JdbcConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [ClickHouseConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-clickhouse/src/main/java/io/datavines/connector/plugin/ClickHouseConnector.java) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java) +- [DorisDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDialect.java) +- [DorisConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java) +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java) +- [DorisExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisExecutor.java) +- [DorisParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java) +- [DorisConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java) + + +## 目录 +1. [简介](#简介) +2. [核心架构](#核心架构) +3. [连接器接口](#连接器接口) +4. [方言处理](#方言处理) +5. [执行器组件](#执行器组件) +6. [数据源客户端](#数据源客户端) +7. [连接池管理](#连接池管理) +8. [JDBC连接器实现](#jdbc连接器实现) +9. [数据库特定实现](#数据库特定实现) +10. [配置构建器](#配置构建器) +11. [连接参数配置](#连接参数配置) +12. [性能优化建议](#性能优化建议) +13. [自定义连接器开发](#自定义连接器开发) + +## 简介 +datavines-connector模块是DataVines数据质量平台的核心组件,负责管理与各种数据源的连接。该模块提供了统一的接口来处理JDBC连接、SQL执行、元数据获取和方言处理等功能。通过SPI机制,支持多种数据库类型,包括MySQL、PostgreSQL、Oracle、Hive、ClickHouse等。模块设计遵循面向接口编程原则,通过抽象基类和工厂模式实现可扩展的连接器架构。 + +**本节不分析具体文件** + +## 核心架构 +datavines-connector模块采用分层架构设计,主要包括连接器、执行器、数据源客户端和方言处理四个核心组件。这些组件通过接口定义契约,实现松耦合和高内聚。 + +```mermaid +graph TD +subgraph "API层" +Connector[连接器接口] +Executor[执行器接口] +DataSourceClient[数据源客户端接口] +Dialect[方言接口] +ConfigBuilder[配置构建器接口] +end +subgraph "JDBC基础实现层" +JdbcConnector[JDBC连接器基类] +BaseJdbcExecutor[JDBC执行器基类] +JdbcDataSourceClient[JDBC数据源客户端] +JdbcDialect[JDBC方言基类] +JdbcConfigBuilder[JDBC配置构建器] +end +subgraph "数据库特定实现层" +MysqlConnector[MySQL连接器] +PostgreSqlConnector[PostgreSQL连接器] +OracleConnector[Oracle连接器] +HiveConnector[Hive连接器] +ClickHouseConnector[ClickHouse连接器] +DorisConnector[Doris连接器] +end +Connector --> JdbcConnector +Executor --> BaseJdbcExecutor +DataSourceClient --> JdbcDataSourceClient +Dialect --> JdbcDialect +ConfigBuilder --> JdbcConfigBuilder +JdbcConnector --> MysqlConnector +JdbcConnector --> PostgreSqlConnector +JdbcConnector --> OracleConnector +JdbcConnector --> HiveConnector +JdbcConnector --> ClickHouseConnector +JdbcConnector --> DorisConnector +JdbcDialect --> MysqlDialect +JdbcDialect --> PostgreSqlDialect +JdbcDialect --> OracleDialect +JdbcDialect --> HiveDialect +JdbcDialect --> ClickHouseDialect +JdbcDialect --> DorisDialect +``` + +**图源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [ConfigBuilder.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [JdbcConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java) + +## 连接器接口 +连接器接口(Connector)定义了数据源连接器的核心功能,包括获取数据库、表、列等元数据信息以及测试连接等功能。该接口通过默认方法提供了基本实现,允许具体连接器根据需要重写特定方法。 + +```mermaid +classDiagram +class Connector { ++getDatabases(GetDatabasesRequestParam) ConnectorResponse ++getTables(GetTablesRequestParam) ConnectorResponse ++getColumns(GetColumnsRequestParam) ConnectorResponse ++getPartitions(ConnectorRequestParam) ConnectorResponse ++testConnect(TestConnectionRequestParam) ConnectorResponse ++keyProperties() String[] +} +class JdbcConnector { ++getDatabases(GetDatabasesRequestParam) ConnectorResponse ++getTables(GetTablesRequestParam) ConnectorResponse ++getColumns(GetColumnsRequestParam) ConnectorResponse ++testConnect(TestConnectionRequestParam) ConnectorResponse ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo ++getMetadataDatabases(Connection) ResultSet ++getMetadataTables(DatabaseMetaData,String,String) ResultSet ++getMetadataColumns(DatabaseMetaData,String,String,String,String) ResultSet ++getPrimaryKeys(DatabaseMetaData,String,String,String) ResultSet +} +class MysqlConnector { ++getMetadataDatabases(Connection) ResultSet ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo +} +class PostgreSqlConnector { ++getMetadataDatabases(Connection) ResultSet ++getMetadataTables(DatabaseMetaData,String,String) ResultSet ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo +} +class OracleConnector { ++getMetadataDatabases(Connection) ResultSet ++getMetadataTables(DatabaseMetaData,String,String) ResultSet ++getMetadataColumns(DatabaseMetaData,String,String,String,String) ResultSet ++getPrimaryKeys(DatabaseMetaData,String,String,String) ResultSet ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo +} +class HiveConnector { ++getMetadataTables(DatabaseMetaData,String,String) ResultSet ++getMetadataColumns(DatabaseMetaData,String,String,String,String) ResultSet ++getPrimaryKeys(DatabaseMetaData,String,String,String) ResultSet ++testConnect(TestConnectionRequestParam) ConnectorResponse ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo +} +class ClickHouseConnector { ++getMetadataTables(DatabaseMetaData,String,String) ResultSet ++getMetadataColumns(DatabaseMetaData,String,String,String,String) ResultSet ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo +} +class DorisConnector { ++getMetadataDatabases(Connection) ResultSet ++getMetadataTables(Connection,String) ResultSet ++getMetadataColumns(Connection,String,String,String) ResultSet ++switchCatalog(Connection,String) void ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo +} +Connector <|.. JdbcConnector : 实现 +JdbcConnector <|.. MysqlConnector : 继承 +JdbcConnector <|.. PostgreSqlConnector : 继承 +JdbcConnector <|.. OracleConnector : 继承 +JdbcConnector <|.. HiveConnector : 继承 +JdbcConnector <|.. ClickHouseConnector : 继承 +JdbcConnector <|.. DorisConnector : 继承 +``` + +**图源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L24-L72) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L42-L283) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java#L28-L45) +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java#L28-L54) +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java#L28-L59) +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java#L28-L75) +- [ClickHouseConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-clickhouse/src/main/java/io/datavines/connector/plugin/ClickHouseConnector.java#L27-L46) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L40-L251) + +**本节源码** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L24-L72) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L42-L283) + +## 方言处理 +方言接口(Dialect)定义了数据库特定的SQL语法和行为,包括标识符引用、查询语句生成、数据类型映射等功能。通过方言机制,连接器可以适应不同数据库的SQL语法差异。 + +```mermaid +classDiagram +class Dialect { ++getDriver() String ++getColumnPrefix() String ++getColumnSuffix() String ++getDialectKeyMap() Map~String,String~ ++getExcludeDatabases() String[] ++getFullQualifiedTableName(String,String,String,boolean) String ++invalidateItemCanOutput() boolean ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++getJDBCType(DataType) String ++getDataType(String) DataType ++quoteIdentifier(String) String ++getQuoteIdentifier() String ++getTableExistsQuery(String) String ++getSchemaQuery(String) String ++getCountQuery(String) String ++getSelectQuery(String) String ++getCreateTableAsSelectStatement(String,String,String) String ++getCreateTableAsSelectStatementFromSql(String,String,String) String ++getCreateTableStatement(String,StructField[],TypeConverter) String ++getInsertAsSelectStatement(String,String,String) String ++getInsertAsSelectStatementFromSql(String,String,String) String ++getErrorDataScript(Map~String,String~) String ++getValidateResultDataScript(Map~String,String~) String ++getPageFromResultSet(Statement,ResultSet,String,int,int) ResultList +} +class JdbcDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++getErrorDataScript(Map~String,String~) String ++getValidateResultDataScript(Map~String,String~) String ++getPageFromResultSet(Statement,ResultSet,String,int,int) ResultList +} +class MysqlDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++supportToBeErrorDataStorage() boolean +} +class OracleDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++getQuoteIdentifier() String ++quoteIdentifier(String) String +} +class HiveDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++invalidateItemCanOutput() boolean ++invalidateItemCanOutputToSelf() boolean +} +class ClickHouseDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++supportToBeErrorDataStorage() boolean +} +class DorisDialect { ++getColumnPrefix() String ++getColumnSuffix() String ++getExcludeDatabases() String[] ++supportToBeErrorDataStorage() boolean +} +Dialect <|.. JdbcDialect : 实现 +JdbcDialect <|.. MysqlDialect : 继承 +JdbcDialect <|.. OracleDialect : 继承 +JdbcDialect <|.. HiveDialect : 继承 +JdbcDialect <|.. ClickHouseDialect : 继承 +JdbcDialect <|.. DorisDialect : 继承 +``` + +**图源** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java#L33-L150) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java#L33-L75) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [ClickHouseConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-clickhouse/src/main/java/io/datavines/connector/plugin/ClickHouseConnector.java) +- [DorisDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDialect.java#L19-L25) + +**本节源码** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java#L33-L150) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java#L33-L75) + +## 执行器组件 +执行器接口(Executor)定义了SQL脚本执行的功能,包括分页查询、列表查询、单条查询和数据删除等操作。执行器通过数据源客户端获取连接,执行SQL并返回结果。 + +```mermaid +classDiagram +class Executor { ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse ++deleteData(ExecuteRequestParam) ConnectorResponse +} +class BaseJdbcExecutor { ++queryForPage(ExecuteRequestParam) ConnectorResponse ++queryForList(ExecuteRequestParam) ConnectorResponse ++queryForOne(ExecuteRequestParam) ConnectorResponse ++query(JdbcTemplate,String,int) ListWithQueryColumn +} +class MysqlExecutor { ++queryForPage(ExecuteRequestParam) ConnectorResponse +} +class PostgreSqlExecutor { ++queryForPage(ExecuteRequestParam) ConnectorResponse +} +class OracleExecutor { ++queryForPage(ExecuteRequestParam) ConnectorResponse +} +class HiveExecutor { ++queryForPage(ExecuteRequestParam) ConnectorResponse +} +class ClickHouseExecutor { ++queryForPage(ExecuteRequestParam) ConnectorResponse +} +class DorisExecutor { ++getDatasourceInfo(Map~String,String~) BaseJdbcDataSourceInfo +} +Executor <|.. BaseJdbcExecutor : 实现 +BaseJdbcExecutor <|.. MysqlExecutor : 继承 +BaseJdbcExecutor <|.. PostgreSqlExecutor : 继承 +BaseJdbcExecutor <|.. OracleExecutor : 继承 +BaseJdbcExecutor <|.. HiveExecutor : 继承 +BaseJdbcExecutor <|.. ClickHouseExecutor : 继承 +BaseJdbcExecutor <|.. DorisExecutor : 继承 +``` + +**图源** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java#L24-L46) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java#L34-L116) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [ClickHouseConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-clickhouse/src/main/java/io/datavines/connector/plugin/ClickHouseConnector.java) +- [DorisExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisExecutor.java#L24-L35) + +**本节源码** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java#L24-L46) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java#L34-L116) + +## 数据源客户端 +数据源客户端(DataSourceClient)接口定义了数据源和数据库连接的获取方法。它负责管理连接池,提供JDBC模板等工具类,是连接器与底层数据库之间的桥梁。 + +```mermaid +classDiagram +class DataSourceClient { ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map~String,Object~) DataSource ++getDataSource(Properties) DataSource ++getConnection(BaseJdbcDataSourceInfo) Connection ++getConnection(Map~String,Object~) Connection ++getConnection(Map~String,Object~,Logger) Connection ++getConnection(Properties) Connection ++getJdbcTemplate(BaseJdbcDataSourceInfo) JdbcTemplate +} +class JdbcDataSourceClient { ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map~String,Object~) DataSource ++getDataSource(Properties) DataSource ++getConnection(BaseJdbcDataSourceInfo) Connection ++getConnection(Map~String,Object~) Connection ++getConnection(Map~String,Object~,Logger) Connection ++getConnection(Properties) Connection ++getJdbcTemplate(BaseJdbcDataSourceInfo) JdbcTemplate +} +DataSourceClient <|.. JdbcDataSourceClient : 实现 +``` + +**图源** +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java#L30-L47) +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java#L32-L88) + +**本节源码** +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java#L30-L47) +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java#L32-L88) + +## 连接池管理 +datavines-connector模块通过JdbcDataSourceManager实现连接池管理。该管理器使用单例模式,为每个数据源配置维护一个独立的连接池,确保连接的高效复用和资源管理。 + +```mermaid +sequenceDiagram +participant Application as 应用程序 +participant Connector as 连接器 +participant DataSourceClient as 数据源客户端 +participant DataSourceManager as 数据源管理器 +participant ConnectionPool as 连接池 +participant Database as 数据库 +Application->>Connector : 请求获取元数据 +Connector->>DataSourceClient : 获取连接 +DataSourceClient->>DataSourceManager : 获取数据源 +DataSourceManager->>ConnectionPool : 从池中获取连接 +alt 连接池中有可用连接 +ConnectionPool-->>DataSourceManager : 返回现有连接 +else 连接池中无可用连接 +ConnectionPool->>Database : 创建新连接 +Database-->>ConnectionPool : 返回新连接 +ConnectionPool-->>DataSourceManager : 返回新连接 +end +DataSourceManager-->>DataSourceClient : 返回数据源 +DataSourceClient-->>Connector : 获取连接 +Connector->>Database : 执行元数据查询 +Database-->>Connector : 返回结果集 +Connector->>Application : 返回元数据 +Connector->>DataSourceClient : 释放连接 +DataSourceClient->>ConnectionPool : 将连接返回池中 +``` + +**图源** +- [JdbcDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java#L32-L88) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L42-L283) + +## JDBC连接器实现 +JDBC连接器基类(JdbcConnector)提供了JDBC连接器的通用实现,包括元数据获取、连接管理、错误处理等功能。它通过模板方法模式,允许子类重写特定数据库的元数据查询方法。 + +```mermaid +flowchart TD +Start([JDBC连接器入口]) --> GetConnection["获取数据库连接"] +GetConnection --> CheckParam["验证参数"] +CheckParam --> ParamValid{"参数有效?"} +ParamValid --> |否| ReturnError["返回错误响应"] +ParamValid --> |是| GetMetadata["获取元数据"] +GetMetadata --> GetDatabases["获取数据库列表"] +GetDatabases --> GetTables["获取表列表"] +GetTables --> GetColumns["获取列信息"] +GetColumns --> GetPrimaryKeys["获取主键信息"] +GetPrimaryKeys --> ProcessResult["处理结果"] +ProcessResult --> BuildResponse["构建响应对象"] +BuildResponse --> ReleaseConnection["释放连接"] +ReleaseConnection --> End([JDBC连接器退出]) +ReturnError --> ReleaseConnection +``` + +**图源** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L42-L283) + +**本节源码** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#L42-L283) + +## 数据库特定实现 +datavines-connector模块为多种数据库提供了特定的连接器实现,每个实现都针对特定数据库的特性和限制进行了优化。 + +### MySQL连接器 +MySQL连接器针对MySQL数据库的特性进行了优化,主要体现在元数据查询方式上。与默认的"show databases"查询不同,MySQL连接器使用DatabaseMetaData.getCatalogs()方法获取数据库列表。 + +**本节源码** +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java#L28-L45) + +### PostgreSQL连接器 +PostgreSQL连接器扩展了表类型支持,除了常规的TABLE和VIEW外,还支持FOREIGN TABLE类型。同时,它重写了元数据查询方法以适应PostgreSQL的模式结构。 + +**本节源码** +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java#L28-L54) + +### Oracle连接器 +Oracle连接器针对Oracle数据库的特殊性进行了多项调整: +1. 使用大写模式名称进行元数据查询 +2. 重写了多个元数据查询方法以适应Oracle的元数据结构 +3. 使用特定的SQL查询获取数据库列表 + +**本节源码** +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java#L28-L59) + +### Hive连接器 +Hive连接器支持Kerberos认证,这是大数据环境中常见的安全机制。连接器在测试连接时会检查Kerberos配置并初始化认证。 + +**本节源码** +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java#L28-L75) + +### ClickHouse连接器 +ClickHouse连接器针对ClickHouse数据库的元数据查询特性进行了优化,使用null作为catalog参数进行查询。 + +**本节源码** +- [ClickHouseConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-clickhouse/src/main/java/io/datavines/connector/plugin/ClickHouseConnector.java#L27-L46) + +### **Doris连接器** **更新** +Doris连接器是datavines-connector模块中新增的重要数据库连接器,专门针对Apache Doris数据库的多目录(catalog)支持进行了完整实现。该连接器具有以下关键特性: + +#### 多目录(catalog)支持 +Doris连接器实现了完整的多目录支持功能,包括: +1. **目录切换机制**:在连接建立后自动切换到指定的目录 +2. **默认目录配置**:设置默认的"internal"目录 +3. **连接参数处理**:支持catalog参数的传递和处理 +4. **URL构建**:支持catalog和database的组合URL构建 + +#### 目录切换机制 +Doris连接器在建立数据库连接后,会根据传入的参数自动执行目录切换操作: + +```mermaid +flowchart TD +Start([建立Doris连接]) --> CheckCatalog["检查catalog参数"] +CheckCatalog --> HasCatalog{"是否指定目录?"} +HasCatalog --> |是| SwitchToCatalog["执行SWITCH目录命令"] +HasCatalog --> |否| SwitchToDefault["切换到默认目录(internal)"] +SwitchToCatalog --> VerifySwitch["验证目录切换结果"] +SwitchToDefault --> VerifySwitch +VerifySwitch --> Success{"切换成功?"} +Success --> |是| Continue["继续执行元数据查询"] +Success --> |否| ThrowError["抛出切换失败异常"] +Continue --> End([连接建立完成]) +ThrowError --> End +``` + +**图源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L72-L85) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L206-L249) + +#### 元数据查询增强 +Doris连接器增强了元数据查询功能,支持目录级别的表和列信息获取: +1. **表查询**:支持按schema查询表列表 +2. **列查询**:支持按catalog、schema、table查询列信息 +3. **目录感知**:能够正确处理目录切换后的元数据查询 + +#### 配置参数支持 +Doris连接器支持以下配置参数: +- **catalog**:目录名称(可选,默认为internal) +- **database**:数据库名称(可选) +- **properties**:连接属性(可选) + +**本节源码** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#L40-L251) +- [DorisDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDialect.java#L19-L25) +- [DorisConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java#L25-L59) +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java#L23-L62) +- [DorisExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisExecutor.java#L24-L35) +- [DorisParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java#L25-L51) +- [DorisConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java#L21-L48) + +## 配置构建器 +配置构建器(ConfigBuilder)接口定义了连接器配置的构建方法,用于生成UI表单配置。基类JdbcConfigBuilder提供了通用的配置项,如主机、端口、数据库、用户名、密码等。 + +```mermaid +classDiagram +class ConfigBuilder { ++build(boolean) String ++buildErrorDataStorage(boolean) String +} +class JdbcConfigBuilder { ++build(boolean) String ++buildErrorDataStorage(boolean) String ++getHostInput(boolean) InputParam ++getPortInput(boolean) InputParam ++getDatabaseInput(boolean) InputParam ++getUserInput(boolean) InputParam ++getPasswordInput(boolean) InputParam ++getPropertiesInput(boolean) InputParam ++getOtherParams(boolean) PluginParams[] +} +class MysqlConfigBuilder { ++getOtherParams(boolean) PluginParams[] +} +class OracleConfigBuilder { ++getOtherParams(boolean) PluginParams[] +} +class HiveConfigBuilder { ++getOtherParams(boolean) PluginParams[] ++getKeytabFile(boolean) InputParam ++getKrb5ConfFile(boolean) InputParam +} +class DorisConfigBuilder { ++getPropertiesInput(boolean) InputParam ++getCatalogInput(boolean) InputParam ++getDatabaseInput(boolean) InputParam ++getPasswordInput(boolean) InputParam +} +ConfigBuilder <|.. JdbcConfigBuilder : 实现 +JdbcConfigBuilder <|.. MysqlConfigBuilder : 继承 +JdbcConfigBuilder <|.. OracleConfigBuilder : 继承 +JdbcConfigBuilder <|.. HiveConfigBuilder : 继承 +JdbcConfigBuilder <|.. DorisConfigBuilder : 继承 +``` + +**图源** +- [ConfigBuilder.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java#L19-L24) +- [JdbcConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java#L36-L150) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) +- [OracleConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java) +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [DorisConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java#L25-L59) + +**本节源码** +- [ConfigBuilder.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java#L19-L24) +- [JdbcConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java#L36-L150) + +## 连接参数配置 +连接参数配置遵循标准化的模式,主要包括以下核心参数: + +| 参数名称 | 描述 | 是否必填 | 示例值 | Doris支持 | +|---------|------|---------|-------|----------| +| host | 数据库主机地址 | 是 | localhost | ✅ | +| port | 数据库端口号 | 是 | 3306 | ✅ | +| database | 数据库名称 | 是 | mydb | ✅ | +| user | 用户名 | 是 | root | ✅ | +| password | 密码 | 否 | password | ✅ | +| properties | 额外连接参数 | 否 | useSSL=false&serverTimezone=UTC | ✅ | +| **catalog** | **目录名称** | **否** | **internal** | **✅ 新增** | + +对于特定数据库,还支持额外的配置参数: +- **Hive**: 支持Kerberos认证相关的keytabFile、krb5ConfFile等参数 +- **Oracle**: 支持SID和服务名等特定参数 +- **PostgreSQL**: 支持schema等模式相关参数 +- **Doris**: 支持catalog目录参数,用于多目录支持 + +**本节源码** +- [DorisConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java#L35-L42) +- [DorisParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java#L28-L49) +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java#L38-L60) + +## 性能优化建议 +为了确保datavines-connector模块的高性能运行,建议采取以下优化措施: + +1. **连接池配置**: 合理设置连接池大小,避免连接过多导致数据库压力过大或连接过少导致性能瓶颈 +2. **查询优化**: 使用分页查询避免一次性获取大量数据,设置合理的fetchSize +3. **元数据缓存**: 对频繁访问的元数据进行缓存,减少数据库查询次数 +4. **连接复用**: 确保连接使用后及时释放回连接池,避免连接泄漏 +5. **批量操作**: 对于大量数据操作,使用批量处理而非逐条处理 +6. **目录切换优化**: 对于Doris连接器,合理使用catalog参数,避免不必要的目录切换操作 + +**本节不分析具体文件** + +## 自定义连接器开发 +开发自定义连接器需要遵循以下步骤: + +1. **实现Connector接口**: 创建新的连接器类,继承JdbcConnector基类 +2. **实现DataSourceClient**: 提供数据源和连接的获取方法 +3. **实现Dialect**: 定义数据库特定的SQL方言 +4. **实现Executor**: 提供SQL执行功能 +5. **实现ConfigBuilder**: 定义连接配置表单 +6. **SPI注册**: 在resources/META-INF/plugins目录下创建SPI配置文件 + +```mermaid +flowchart TD +Start([开始开发自定义连接器]) --> CreateClass["创建连接器类
继承JdbcConnector"] +CreateClass --> ImplementMethods["实现必要方法
getDatasourceInfo等"] +ImplementMethods --> CreateDialect["创建方言类
继承JdbcDialect"] +CreateDialect --> OverrideMethods["重写方言方法
如getExcludeDatabases"] +OverrideMethods --> CreateExecutor["创建执行器类
继承BaseJdbcExecutor"] +CreateExecutor --> ImplementExecutor["实现执行器方法"] +ImplementExecutor --> CreateConfigBuilder["创建配置构建器
继承JdbcConfigBuilder"] +CreateConfigBuilder --> CustomizeForm["自定义配置表单"] +CustomizeForm --> SPIRegistration["SPI注册
创建META-INF/plugins文件"] +SPIRegistration --> Test["测试连接器功能"] +Test --> Document["编写文档"] +Document --> End([完成自定义连接器开发]) +``` + +**本节不分析具体文件** \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/\350\277\236\346\216\245\345\231\250API\346\240\270\345\277\203.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/\350\277\236\346\216\245\345\231\250API\346\240\270\345\277\203.md" new file mode 100644 index 00000000..4ae0d2d0 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-connector\346\250\241\345\235\227/\350\277\236\346\216\245\345\231\250API\346\240\270\345\277\203.md" @@ -0,0 +1,636 @@ +# 连接器API核心 + + +**本文档中引用的文件** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [ConfigBuilder.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java) +- [ParameterConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ParameterConverter.java) +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java) +- [StatementParser.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/StatementParser.java) +- [StatementSplitter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/StatementSplitter.java) +- [MetricScript.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/MetricScript.java) +- [TypeConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/TypeConverter.java) +- [ResultList.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultList.java) +- [QueryColumn.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/QueryColumn.java) +- [JdbcUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/JdbcUtils.java) +- [SqlUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/SqlUtils.java) +- [ConnectorResponse.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java) +- [TestConnectionRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [MongodbConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java) +- [MaxComputeConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-maxcompute/src/main/java/io/datavines/connector/plugin/MaxComputeConnector.java) +- [DatabendConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-databend/src/main/java/io/datavines/connector/plugin/DatabendConnector.java) +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [PrestoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java) +- [TrinoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoConnector.java) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java) +- [ErrorDataStorageController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/ErrorDataStorageController.java) + + +## 更新摘要 +**所做的更改** +- 更新了Connector接口的testConnect方法说明,强调了改进的错误报告机制 +- 新增了ConnectorResponse错误消息处理的最佳实践章节 +- 更新了连接器测试连接的错误处理流程图 +- 增强了故障排除指南中关于错误报告的内容 + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [错误报告机制改进](#错误报告机制改进) +7. [依赖分析](#依赖分析) +8. [性能考虑](#性能考虑) +9. [故障排除指南](#故障排除指南) +10. [结论](#结论) + +## 引言 +本文档深入解析DataVines连接器API模块的设计与实现,重点阐述Connector、DataSourceClient、Dialect和Executor等核心接口的契约与职责。文档详细描述了基于SPI的插件机制如何实现连接器的可扩展性,分析了连接参数构建、SQL执行、元数据获取和方言处理的抽象设计。通过接口契约的详细说明,包括方法签名、参数约束和异常处理,为开发者提供清晰的实现指导。同时,文档包含连接器生命周期管理的最佳实践和线程安全考虑。 + +**更新** 本次更新重点关注连接器错误报告机制的改进,所有连接器的testConnect方法都增强了详细的异常捕获和错误消息返回,确保错误信息的一致性和可诊断性。 + +## 项目结构 +datavines-connector-api模块是DataVines数据质量平台的核心组件之一,提供了连接各种数据源的标准接口和抽象。该模块采用接口驱动的设计,通过SPI(Service Provider Interface)机制实现插件化扩展,允许为不同的数据库系统(如MySQL、PostgreSQL、ClickHouse等)提供具体的实现。 + +```mermaid +graph TD +subgraph "datavines-connector-api" +Connector[Connector] +DataSourceClient[DataSourceClient] +Dialect[Dialect] +Executor[Executor] +ConnectorFactory[ConnectorFactory] +ConfigBuilder[ConfigBuilder] +ParameterConverter[ParameterConverter] +ResponseConverter[ResponseConverter] +StatementParser[StatementParser] +StatementSplitter[StatementSplitter] +MetricScript[MetricScript] +TypeConverter[TypeConverter] +end +subgraph "实体与工具" +entity[entity] +utils[utils] +end +ConnectorFactory --> Connector +ConnectorFactory --> DataSourceClient +ConnectorFactory --> Dialect +ConnectorFactory --> Executor +ConnectorFactory --> ConfigBuilder +ConnectorFactory --> ParameterConverter +ConnectorFactory --> ResponseConverter +ConnectorFactory --> StatementParser +ConnectorFactory --> StatementSplitter +ConnectorFactory --> MetricScript +ConnectorFactory --> TypeConverter +Dialect --> JdbcUtils +Dialect --> SqlUtils +entity --> JdbcUtils +entity --> SqlUtils +``` + +**图表来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [JdbcUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/JdbcUtils.java) +- [SqlUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/SqlUtils.java) + +**章节来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +## 核心组件 +datavines-connector-api模块的核心在于其定义的一系列接口,这些接口共同构成了一个可扩展的连接器框架。`ConnectorFactory`作为入口点,通过SPI机制加载具体的连接器实现。`Connector`接口负责元数据的获取,如数据库、表和列的列表。`DataSourceClient`负责管理数据源连接的生命周期,提供获取`DataSource`、`Connection`和`JdbcTemplate`的能力。`Dialect`接口封装了特定数据库的SQL方言和元数据处理逻辑,是实现数据库兼容性的关键。`Executor`接口则负责SQL语句的执行,包括查询和数据操作。`ParameterConverter`和`ResponseConverter`分别处理连接参数的转换和执行结果的格式化,而`ConfigBuilder`用于构建前端配置表单。 + +**章节来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +## 架构概述 +datavines-connector-api的架构设计遵循了依赖倒置原则(DIP),高层模块(如数据质量检查服务)依赖于抽象(接口),而不是具体的实现。这种设计使得系统可以轻松地集成新的数据源,而无需修改核心业务逻辑。 + +```mermaid +classDiagram +class ConnectorFactory { ++getCategory() String ++getConnector() Connector ++getDataSourceClient() DataSourceClient ++getDialect() Dialect ++getExecutor() Executor ++getConfigBuilder() ConfigBuilder ++getParameterConverter() ParameterConverter ++getResponseConverter() ResponseConverter ++getStatementParser() StatementParser ++getStatementSplitter() StatementSplitter ++getMetricScript() MetricScript ++getTypeConverter() TypeConverter ++showInFrontend() Boolean +} +class Connector { ++getDatabases(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++getPartitions(param) ConnectorResponse ++testConnect(param) ConnectorResponse ++keyProperties() String[] +} +class DataSourceClient { ++getDataSource(info) DataSource ++getDataSource(configMap) DataSource ++getDataSource(properties) DataSource ++getConnection(info) Connection ++getConnection(configMap) Connection ++getConnection(configMap, logger) Connection ++getConnection(properties) Connection ++getJdbcTemplate(info) JdbcTemplate +} +class Dialect { ++getDriver() String ++getColumnPrefix() String ++getColumnSuffix() String ++getDialectKeyMap() Map~String,String~ ++getExcludeDatabases() String[] ++getFullQualifiedTableName(db, schema, table, needQuote) String ++invalidateItemCanOutput() boolean ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++getJDBCType(dataType) String ++getDataType(jdbcType) DataType ++quoteIdentifier(entity) String ++getQuoteIdentifier() String ++getTableExistsQuery(table) String ++getSchemaQuery(table) String ++getCountQuery(table) String ++getSelectQuery(table) String ++getCreateTableAsSelectStatement(src, targetDb, targetTable) String ++getCreateTableAsSelectStatementFromSql(src, targetDb, targetTable) String ++getCreateTableStatement(table, fields, typeConverter) String ++getInsertAsSelectStatement(src, targetDb, targetTable) String ++getInsertAsSelectStatementFromSql(src, targetDb, targetTable) String ++getErrorDataScript(configMap) String ++getValidateResultDataScript(configMap) String ++getPageFromResultSet(statement, rs, table, start, end) ResultList +} +class Executor { ++queryForPage(param) ConnectorResponse ++queryForList(param) ConnectorResponse ++queryForOne(param) ConnectorResponse ++deleteData(param) ConnectorResponse +} +class ConfigBuilder { ++build(isEn) String ++buildErrorDataStorage(isEn) String +} +class ParameterConverter { ++converter(parameter) Map~String,Object~ ++getConnectorUUID(parameter) String +} +class ResponseConverter { +} +class StatementParser { ++parseStatement(statement) StatementMetadataFragment +} +class StatementSplitter { ++splitStatements(body) String[] +} +class MetricScript { ++selectFromTable() String ++baseActualValue(uniqueKey) String ++baseDirectActualValue(uniqueKey, invalidateItemsSql) String ++avgActualValue(uniqueKey) String ++avgLengthActualValue(uniqueKey) String ++countDistinctActualValue(uniqueKey) String ++histogramActualValue(uniqueKey, where) String ++maxActualValue(uniqueKey) String ++maxLengthActualValue(uniqueKey) String ++minActualValue(uniqueKey) String ++minLengthActualValue(uniqueKey) String ++stdDevActualValue(uniqueKey) String ++sumActualValue(uniqueKey) String ++varianceActualValue(uniqueKey) String ++groupByHavingCountForUnique() String ++groupByHavingCountForDuplicate() String ++columnInEnums() String ++columnNotInEnums() String ++columnNotNull() String ++columnIsNull() String ++columnLengthCompare() String ++columnNotMatchRegex() String ++columnMatchRegex() String ++columnGteMin() String ++columnLteMax() String ++columnIsBlank() String ++timeBetweenWithFormat() String ++dailyAvg(uniqueKey) String ++last7DayAvg(uniqueKey) String ++last30DayAvg(uniqueKey) String ++monthlyAvg(uniqueKey) String ++weeklyAvg(uniqueKey) String +} +class TypeConverter { ++convert(originType) DataType ++convertToOriginType(dataType) String +} +ConnectorFactory <|-- JdbcConnectorFactory : "实现" +ConnectorFactory <|-- MysqlConnectorFactory : "实现" +ConnectorFactory <|-- ClickHouseConnectorFactory : "实现" +ConnectorFactory <|-- TrinoConnectorFactory : "实现" +ConnectorFactory --> Connector : "创建" +ConnectorFactory --> DataSourceClient : "创建" +ConnectorFactory --> Dialect : "创建" +ConnectorFactory --> Executor : "创建" +ConnectorFactory --> ConfigBuilder : "创建" +ConnectorFactory --> ParameterConverter : "创建" +ConnectorFactory --> ResponseConverter : "创建" +ConnectorFactory --> StatementParser : "创建" +ConnectorFactory --> StatementSplitter : "创建" +ConnectorFactory --> MetricScript : "创建" +ConnectorFactory --> TypeConverter : "创建" +Dialect --> TypeConverter : "使用" +Executor --> DataSourceClient : "使用" +SqlUtils --> Dialect : "使用" +JdbcUtils --> Dialect : "使用" +JdbcUtils --> TypeConverter : "使用" +``` + +**图表来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [ConfigBuilder.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java) +- [ParameterConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ParameterConverter.java) +- [ResponseConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java) +- [StatementParser.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/StatementParser.java) +- [StatementSplitter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/StatementSplitter.java) +- [MetricScript.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/MetricScript.java) +- [TypeConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/TypeConverter.java) +- [JdbcUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/JdbcUtils.java) +- [SqlUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/SqlUtils.java) + +## 详细组件分析 + +### Connector接口分析 +`Connector`接口是所有数据源连接器的基础,定义了与数据源进行交互的核心元数据操作。它提供了获取数据库列表、表列表、列列表、分区信息以及测试连接的功能。该接口采用默认方法(default methods)模式,允许实现类只覆盖其支持的操作,对于不支持的操作返回null。`keyProperties()`方法返回连接器的关键属性列表,用于生成连接器的唯一标识。 + +**更新** testConnect方法现在要求所有连接器实现都提供详细的错误报告,确保用户能够获得一致的错误信息体验。 + +```mermaid +classDiagram +class Connector { ++getDatabases(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++getPartitions(param) ConnectorResponse ++testConnect(param) ConnectorResponse ++keyProperties() String[] +} +class GetDatabasesRequestParam { ++dataSourceId Long +} +class GetTablesRequestParam { ++dataSourceId Long ++database String +} +class GetColumnsRequestParam { ++dataSourceId Long ++database String ++table String +} +class TestConnectionRequestParam { ++dataSourceId Long +} +class ConnectorResponse { ++success boolean ++msg String ++data Object +} +Connector <|-- JdbcConnector : "实现" +Connector <|-- MysqlConnector : "实现" +Connector <|-- ClickHouseConnector : "实现" +GetDatabasesRequestParam <.. Connector : "参数" +GetTablesRequestParam <.. Connector : "参数" +GetColumnsRequestParam <.. Connector : "参数" +TestConnectionRequestParam <.. Connector : "参数" +ConnectorResponse <.. Connector : "返回值" +``` + +**图表来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) + +**章节来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) + +### DataSourceClient接口分析 +`DataSourceClient`接口负责管理与数据源的连接。它提供了多种方式来获取`DataSource`、`Connection`和`JdbcTemplate`,支持从`BaseJdbcDataSourceInfo`对象、`Map`配置映射或`Properties`对象创建连接。这种设计提供了极大的灵活性,允许连接器根据不同的配置源进行初始化。该接口是连接器与底层JDBC驱动之间的桥梁,确保了连接的正确建立和管理。 + +```mermaid +classDiagram +class DataSourceClient { ++getDataSource(info) DataSource ++getDataSource(configMap) DataSource ++getDataSource(properties) DataSource ++getConnection(info) Connection ++getConnection(configMap) Connection ++getConnection(configMap, logger) Connection ++getConnection(properties) Connection ++getJdbcTemplate(info) JdbcTemplate +} +class BaseJdbcDataSourceInfo { ++id Long ++name String ++type String ++config Map~String,Object~ +} +class DataSource { +} +class Connection { +} +class JdbcTemplate { +} +DataSourceClient <|-- JdbcDataSourceClient : "实现" +DataSourceClient <|-- MysqlDataSourceClient : "实现" +DataSourceClient <|-- ClickHouseDataSourceClient : "实现" +BaseJdbcDataSourceInfo <.. DataSourceClient : "参数" +DataSource <.. DataSourceClient : "返回值" +Connection <.. DataSourceClient : "返回值" +JdbcTemplate <.. DataSourceClient : "返回值" +``` + +**图表来源** +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) + +**章节来源** +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) + +### Dialect接口分析 +`Dialect`接口是实现数据库兼容性的核心。它封装了特定数据库的SQL方言、元数据处理和类型转换逻辑。接口提供了生成数据库驱动类名、标识符引号、各种SQL查询语句(如检查表是否存在、获取表结构、创建表等)的方法。`getPageFromResultSet`方法用于从结果集中提取分页数据,是实现数据预览功能的关键。`TypeConverter`被`Dialect`使用,以实现数据库特定类型与DataVines通用`DataType`枚举之间的双向转换。 + +```mermaid +classDiagram +class Dialect { ++getDriver() String ++getColumnPrefix() String ++getColumnSuffix() String ++getDialectKeyMap() Map~String,String~ ++getExcludeDatabases() String[] ++getFullQualifiedTableName(db, schema, table, needQuote) String ++invalidateItemCanOutput() boolean ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++getJDBCType(dataType) String ++getDataType(jdbcType) DataType ++quoteIdentifier(entity) String ++getQuoteIdentifier() String ++getTableExistsQuery(table) String ++getSchemaQuery(table) String ++getCountQuery(table) String ++getSelectQuery(table) String ++getCreateTableAsSelectStatement(src, targetDb, targetTable) String ++getCreateTableAsSelectStatementFromSql(src, targetDb, targetTable) String ++getCreateTableStatement(table, fields, typeConverter) String ++getInsertAsSelectStatement(src, targetDb, targetTable) String ++getInsertAsSelectStatementFromSql(src, targetDb, targetTable) String ++getErrorDataScript(configMap) String ++getValidateResultDataScript(configMap) String ++getPageFromResultSet(statement, rs, table, start, end) ResultList +} +class TypeConverter { ++convert(originType) DataType ++convertToOriginType(dataType) String +} +class DataType { +<> +STRING +INT +LONG +FLOAT +DOUBLE +BOOLEAN +DATE +TIMESTAMP +DECIMAL +} +class ResultList { ++resultList Map[]String,Object~~ +} +Dialect <|-- JdbcDialect : "实现" +Dialect <|-- MysqlDialect : "实现" +Dialect <|-- ClickHouseDialect : "实现" +Dialect <|-- TrinoDialect : "实现" +TypeConverter <.. Dialect : "使用" +DataType <.. TypeConverter : "使用" +ResultList <.. Dialect : "返回值" +``` + +**图表来源** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [TypeConverter.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/TypeConverter.java) + +**章节来源** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) + +### Executor接口分析 +`Executor`接口负责执行SQL脚本和查询。它定义了`queryForPage`、`queryForList`和`queryForOne`等方法,用于执行查询并返回分页、列表或单条记录的结果。`deleteData`方法用于执行数据删除操作。该接口的实现通常会依赖`DataSourceClient`来获取数据库连接,并使用`Dialect`来处理特定于数据库的查询逻辑。`SqlUtils`工具类为`Executor`的实现提供了从`ResultSet`提取数据的通用方法。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Executor as "Executor" +participant DataSourceClient as "DataSourceClient" +participant Connection as "Connection" +participant Statement as "Statement" +participant ResultSet as "ResultSet" +participant SqlUtils as "SqlUtils" +Client->>Executor : queryForPage(param) +Executor->>DataSourceClient : getConnection(configMap) +DataSourceClient-->>Executor : Connection +Executor->>Connection : createStatement() +Connection-->>Executor : Statement +Executor->>Statement : executeQuery(sql) +Statement-->>Executor : ResultSet +Executor->>SqlUtils : getListWithHeaderFromResultSet(rs, start, end) +SqlUtils-->>Executor : ResultListWithColumns +Executor-->>Client : ConnectorResponse +``` + +**图表来源** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [SqlUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/SqlUtils.java) + +**章节来源** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) + +### ConnectorFactory接口分析 +`ConnectorFactory`是整个连接器API的入口点和工厂。它被`@SPI`注解标记,表明它是一个服务提供者接口,可以通过Java的SPI机制动态加载。每个具体的连接器(如MySQL、PostgreSQL)都必须提供一个`ConnectorFactory`的实现。该工厂负责创建连接器所需的所有组件:`Connector`、`DataSourceClient`、`Dialect`、`Executor`等。`getCategory()`方法返回连接器的类别(如"jdbc"),`showInFrontend()`方法决定该连接器是否在前端UI中显示。 + +```mermaid +classDiagram +class ConnectorFactory { +<> ++getCategory() String ++getConnector() Connector ++getDataSourceClient() DataSourceClient ++getDialect() Dialect ++getExecutor() Executor ++getConfigBuilder() ConfigBuilder ++getParameterConverter() ParameterConverter ++getResponseConverter() ResponseConverter ++getStatementParser() StatementParser ++getStatementSplitter() StatementSplitter ++getMetricScript() MetricScript ++getTypeConverter() TypeConverter ++showInFrontend() Boolean +} +class SPI { +<> +} +class JdbcConnectorFactory { ++getCategory() String ++getConnector() Connector ++getDataSourceClient() DataSourceClient ++getDialect() Dialect ++getExecutor() Executor ++getConfigBuilder() ConfigBuilder ++getParameterConverter() ParameterConverter ++getTypeConverter() TypeConverter +} +class MysqlConnectorFactory { ++getCategory() String ++getConnector() Connector ++getDataSourceClient() DataSourceClient ++getDialect() Dialect ++getExecutor() Executor ++getConfigBuilder() ConfigBuilder ++getParameterConverter() ParameterConverter ++getTypeConverter() TypeConverter +} +SPI --> ConnectorFactory : "标记" +ConnectorFactory <|-- JdbcConnectorFactory : "实现" +ConnectorFactory <|-- MysqlConnectorFactory : "实现" +JdbcConnectorFactory --> JdbcConnector : "创建" +JdbcConnectorFactory --> JdbcDataSourceClient : "创建" +JdbcConnectorFactory --> JdbcDialect : "创建" +JdbcConnectorFactory --> BaseJdbcExecutor : "创建" +JdbcConnectorFactory --> JdbcConfigBuilder : "创建" +JdbcConnectorFactory --> JdbcParameterConverter : "创建" +JdbcConnectorFactory --> JdbcTypeConverter : "创建" +``` + +**图表来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +**章节来源** +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +## 错误报告机制改进 + +### 统一的错误报告标准 +所有连接器的testConnect方法现在都实现了统一的错误报告机制,确保用户能够获得一致且有用的错误信息。这种改进提高了系统的可诊断性和用户体验。 + +```mermaid +sequenceDiagram +participant UI as "用户界面" +participant Controller as "数据源控制器" +participant Service as "数据源服务" +participant Factory as "连接器工厂" +participant Connector as "连接器实现" +participant DB as "数据库" +UI->>Controller : 测试连接请求 +Controller->>Service : testConnect(param) +Service->>Factory : getOrCreatePlugin(type) +Factory-->>Service : ConnectorFactory +Service->>Connector : testConnect(param) +Connector->>DB : 建立连接 +DB-->>Connector : 连接成功/失败 +alt 连接成功 +Connector-->>Service : ConnectorResponse(SUCCESS, true, null) +else 连接失败 +Connector->>Connector : 捕获异常 +Connector-->>Service : ConnectorResponse(ERROR, false, 错误消息) +end +Service-->>Controller : ConnectorResponse +Controller-->>UI : 显示连接结果 +``` + +**图表来源** +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [MongodbConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java) +- [MaxComputeConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-maxcompute/src/main/java/io/datavines/connector/plugin/MaxComputeConnector.java) + +### 错误消息处理最佳实践 +连接器实现中的错误消息处理遵循以下最佳实践: + +1. **详细的异常捕获**:所有testConnect方法都使用try-catch块捕获可能的异常 +2. **有意义的错误消息**:错误消息应该清楚地描述问题所在 +3. **一致的状态码**:使用ConnectorResponse.Status.ERROR表示失败状态 +4. **完整的错误上下文**:在日志中记录详细的错误上下文信息 + +**章节来源** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [MongodbConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java) +- [MaxComputeConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-maxcompute/src/main/java/io/datavines/connector/plugin/MaxComputeConnector.java) +- [DatabendConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-databend/src/main/java/io/datavines/connector/plugin/DatabendConnector.java) +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [PrestoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java) +- [TrinoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoConnector.java) + +## 依赖分析 +datavines-connector-api模块通过SPI机制与具体的连接器实现(如`datavines-connector-jdbc`、`datavines-connector-mysql`)进行解耦。核心API模块定义了所有必要的接口,而具体的实现模块则提供这些接口的实例。`datavines-common`模块提供了通用的配置、参数和异常处理类,被连接器API所依赖。`datavines-spi`模块提供了SPI加载机制,是实现插件化扩展的基础。 + +```mermaid +graph TD +datavines_connector_api[datavines-connector-api] +datavines_common[datavines-common] +datavines_spi[datavines-spi] +datavines_connector_jdbc[datavines-connector-jdbc] +datavines_connector_mysql[datavines-connector-mysql] +datavines_connector_clickhouse[datavines-connector-clickhouse] +datavines_connector_api --> datavines_common +datavines_connector_api --> datavines_spi +datavines_connector_jdbc --> datavines_connector_api +datavines_connector_mysql --> datavines_connector_api +datavines_connector_clickhouse --> datavines_connector_api +``` + +**图表来源** +- [pom.xml](file://datavines-connector/datavines-connector-api/pom.xml) +- [pom.xml](file://datavines-connector/datavines-connector-jdbc/pom.xml) +- [pom.xml](file://datavines-connector/datavines-connector-mysql/pom.xml) + +**章节来源** +- [pom.xml](file://datavines-connector/datavines-connector-api/pom.xml) + +## 性能考虑 +在实现连接器时,性能是一个重要的考虑因素。`DataSourceClient`应确保`DataSource`的复用,避免为每次操作都创建新的连接池。`Executor`在执行查询时,应合理设置查询超时时间,并在处理大型结果集时使用分页。`Dialect`的`getPageFromResultSet`方法通过`ResultSet.absolute()`来实现分页,这在某些数据库上可能效率不高,应根据具体数据库的特性进行优化。此外,`ParameterConverter`中的`getConnectorUUID`方法使用MD5哈希生成连接器的唯一标识,这有助于缓存和连接池管理。 + +## 故障排除指南 +当连接器出现问题时,应首先检查`DataSourceClient`能否成功建立连接。如果连接失败,检查连接参数(URL、用户名、密码)是否正确,并确认数据库驱动是否已正确加载。如果查询执行失败,检查`Dialect`生成的SQL语句是否符合目标数据库的语法。可以启用日志记录来跟踪`Executor`执行的SQL语句和返回的错误信息。对于元数据获取问题,检查`Connector`接口的实现是否正确处理了`GetDatabasesRequestParam`、`GetTablesRequestParam`等请求参数。 + +**更新** 现在所有连接器都实现了统一的错误报告机制,用户可以通过以下方式获取详细的错误信息: + +1. **检查服务器日志**:连接器会在日志中记录详细的错误上下文 +2. **验证连接参数**:确保连接字符串、用户名和密码正确无误 +3. **网络连通性**:确认客户端能够访问目标数据库服务器 +4. **权限验证**:检查数据库用户是否有足够的权限 + +**章节来源** +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [ConnectorResponse.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java) + +## 结论 +datavines-connector-api模块通过精心设计的接口和SPI插件机制,为DataVines平台提供了强大的数据源连接能力。其核心接口`Connector`、`DataSourceClient`、`Dialect`和`Executor`清晰地划分了职责,使得开发者可以轻松地为新的数据库系统创建连接器。`ConnectorFactory`作为统一的工厂,确保了组件的可配置性和可扩展性。 + +**更新** 本次更新显著改进了连接器的错误报告机制,所有连接器的testConnect方法现在都提供了详细、一致的错误信息,大大提升了系统的可诊断性和用户体验。通过遵循本文档中描述的设计原则和最佳实践,可以构建出高效、稳定且易于维护的连接器实现。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/datavines-engine\346\250\241\345\235\227.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/datavines-engine\346\250\241\345\235\227.md" new file mode 100644 index 00000000..c95733b8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/datavines-engine\346\250\241\345\235\227.md" @@ -0,0 +1,362 @@ +# datavines-engine模块 + + +**本文档中引用的文件** +- [README.md](file://datavines-engine/README.md) +- [pom.xml](file://datavines-engine/pom.xml) +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [DataVinesConfigurationManager.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/DataVinesConfigurationManager.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) + +## 引言 + +datavines-engine模块是DataVines数据质量平台的核心执行引擎,负责任务执行、资源配置、引擎抽象和作业配置构建等关键功能。该模块设计为可扩展的架构,支持多种执行引擎,包括Flink、Spark和本地执行模式。通过标准化的接口和配置管理,datavines-engine实现了不同执行环境之间的无缝切换和统一管理。 + +## 项目结构 + +datavines-engine模块采用模块化设计,包含多个子模块,每个子模块负责特定的功能。这种设计使得系统具有良好的可扩展性和维护性。 + +```mermaid +graph TD +A[datavines-engine] --> B[datavines-engine-api] +A --> C[datavines-engine-core] +A --> D[datavines-engine-config] +A --> E[datavines-engine-executor] +A --> F[datavines-engine-common] +A --> G[datavines-engine-plugins] +G --> H[datavines-engine-flink] +G --> I[datavines-engine-spark] +G --> J[datavines-engine-local] +G --> K[datavines-engine-livy] +``` + +**图源** +- [pom.xml](file://datavines-engine/pom.xml) + +**本节来源** +- [README.md](file://datavines-engine/README.md) +- [pom.xml](file://datavines-engine/pom.xml) + +## 核心组件 + +datavines-engine模块的核心组件包括引擎执行器、运行时环境、执行接口、组件接口和插件接口。这些组件共同构成了执行引擎的基础架构。 + +**本节来源** +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java) + +## 架构概述 + +datavines-engine模块的架构设计遵循了分层和模块化的原则,确保了系统的可扩展性和可维护性。 + +```mermaid +classDiagram +class EngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++after() ++cancel() ++isCancel() ++getProcessResult() ++getTaskRequest() +} +class RuntimeEnvironment { ++prepare() ++getExecution() +} +class Execution { ++execute(SR[], TF[], SK[]) ++stop() ++prepare() +} +class Component { ++prepare(RuntimeEnvironment) +} +class Plugin { ++setConfig(Config) ++getConfig() ++checkConfig() +} +class BaseDataVinesBootstrap { ++execute(String[]) ++stop() ++parseConfigAndExecute(String) ++checkConfig(Component[]...) ++prepare(RuntimeEnvironment, Component[]...) +} +EngineExecutor <|-- AbstractEngineExecutor +RuntimeEnvironment <|-- ConcreteRuntimeEnvironment +Execution <|-- ConcreteExecution +Component <|-- ConcreteComponent +Plugin <|-- ConcretePlugin +BaseDataVinesBootstrap <|-- ConcreteBootstrap +AbstractEngineExecutor <|-- AbstractLivyEngineExecutor +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +``` + +**图源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +## 详细组件分析 + +### 引擎执行器分析 + +引擎执行器是datavines-engine模块的核心组件之一,负责任务的执行和管理。 + +#### 引擎执行器接口 +```mermaid +classDiagram +class EngineExecutor { +<> ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++after() ++cancel() ++isCancel() ++getProcessResult() ++getTaskRequest() +} +``` + +**图源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) + +#### 抽象引擎执行器 +```mermaid +classDiagram +class AbstractEngineExecutor { +-JobExecutionRequest jobExecutionRequest +-Logger logger +-volatile boolean cancel +-ProcessResult processResult ++AbstractEngineExecutor() ++logHandle(String[]) ++isCancel() +-buildCommand() +} +EngineExecutor <|-- AbstractEngineExecutor +``` + +**图源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) + +#### Livy引擎执行器 +```mermaid +classDiagram +class AbstractLivyEngineExecutor { +-LivyCommandProcess livyCommandProcess ++cancel() +} +AbstractEngineExecutor <|-- AbstractLivyEngineExecutor +``` + +**图源** +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) + +#### Yarn引擎执行器 +```mermaid +classDiagram +class AbstractYarnEngineExecutor { +-ShellCommandProcess shellCommandProcess ++cancel() +-killYarnApplication() +} +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +``` + +**图源** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) + +**本节来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) + +### 运行时环境分析 + +运行时环境负责准备执行环境和获取执行实例。 + +```mermaid +classDiagram +class RuntimeEnvironment { +<> ++prepare() ++getExecution() +} +class Execution { +<> ++execute(SR[], TF[], SK[]) ++stop() ++prepare() +} +``` + +**图源** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + +**本节来源** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + +### 组件和插件分析 + +组件和插件接口为datavines-engine提供了可扩展的基础。 + +```mermaid +classDiagram +class Component { +<> ++prepare(RuntimeEnvironment) +} +class Plugin { +<> ++setConfig(Config) ++getConfig() ++checkConfig() +} +Component <|-- Plugin +``` + +**图源** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java) + +**本节来源** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java) + +### 引擎抽象分析 + +引擎抽象层通过BaseDataVinesBootstrap类提供了统一的执行入口。 + +```mermaid +classDiagram +class BaseDataVinesBootstrap { +-static final Logger logger +-Execution execution ++execute(String[]) ++stop() +-parseConfigAndExecute(String) +-checkConfig(Component[]...) +-prepare(RuntimeEnvironment, Component[]...) +-showConfigError(Throwable) +-showFatalError(Throwable) +} +``` + +**图源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +**本节来源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +### 作业配置构建分析 + +作业配置构建器负责将标准的DataVines配置转换为特定引擎的配置。 + +```mermaid +classDiagram +class BaseJobConfigurationBuilder { +-DataVinesJobConfig configuration +-Map~String, String~ inputParameter +-JobExecutionParameter jobExecutionParameter +-JobExecutionInfo jobExecutionInfo +-Map~String, Map~String, String~~ metric2InputParameter ++init(Map~String, String~, JobExecutionInfo) ++buildName() ++buildEnvConfig() ++buildSourceConfigs() ++buildTransformConfigs() ++build() +-getEnvConfig() +-getSourceConfigs() +-getValidateResultDataSourceConfig() +-getValidateResultDataSinkConfig() +-getMetricUniqueKey() +} +class DataVinesConfigurationManager { ++buildDataQualityConfiguration(JobConfigurationBuilder) ++generateConfiguration(JobType, Map~String, String~, JobExecutionInfo) +} +``` + +**图源** +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [DataVinesConfigurationManager.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/DataVinesConfigurationManager.java) + +**本节来源** +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [DataVinesConfigurationManager.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/DataVinesConfigurationManager.java) + +## 依赖分析 + +datavines-engine模块依赖于datavines-common模块,提供了基础的配置和实体类。 + +```mermaid +graph TD +A[datavines-engine] --> B[datavines-common] +B --> C[Config] +B --> D[JobExecutionRequest] +B --> E[ProcessResult] +A --> F[SPI] +F --> G[PluginLoader] +``` + +**图源** +- [pom.xml](file://datavines-engine/pom.xml) + +**本节来源** +- [pom.xml](file://datavines-engine/pom.xml) + +## 性能考虑 + +datavines-engine模块在设计时考虑了性能优化,通过异步执行、资源管理和错误处理等机制确保了高效的任务执行。 + +## 故障排查指南 + +当遇到执行问题时,可以按照以下步骤进行排查: + +1. 检查配置文件是否正确 +2. 查看日志输出,定位错误信息 +3. 确认资源是否充足 +4. 检查网络连接是否正常 +5. 验证插件是否正确加载 + +**本节来源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +## 结论 + +datavines-engine模块通过模块化和可扩展的设计,提供了一个强大而灵活的执行引擎框架。它支持多种执行模式,包括Flink、Spark和本地执行,并通过标准化的接口和配置管理实现了不同执行环境之间的无缝切换。该模块的设计充分考虑了性能、可维护性和可扩展性,为DataVines数据质量平台提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\344\275\234\344\270\232\351\205\215\347\275\256\346\236\204\345\273\272.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\344\275\234\344\270\232\351\205\215\347\275\256\346\236\204\345\273\272.md" new file mode 100644 index 00000000..9783b47e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\344\275\234\344\270\232\351\205\215\347\275\256\346\236\204\345\273\272.md" @@ -0,0 +1,295 @@ +# 作业配置构建 + + +**本文档中引用的文件** +- [JobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [MetricParserUtils.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/MetricParserUtils.java) +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) +- [SourceConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SourceConfig.java) +- [TransformConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/TransformConfig.java) +- [SinkConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/SinkConfig.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件分析](#核心组件分析) +3. [配置构建流程](#配置构建流程) +4. [参数验证与默认值填充](#参数验证与默认值填充) +5. [配置优化机制](#配置优化机制) +6. [自定义配置构建器开发指南](#自定义配置构建器开发指南) +7. [最佳实践](#最佳实践) +8. [结论](#结论) + +## 引言 +作业配置构建系统是DataVines数据质量平台的核心组件,负责将高层业务逻辑转换为底层执行配置。该系统通过JobConfigurationBuilder接口和BaseJobConfigurationBuilder抽象类提供灵活的配置构建能力,同时利用MetricParserUtils工具类实现度量指标的解析和处理。本文档详细说明了该系统的架构、工作流程和扩展机制,为开发者提供全面的技术参考。 + +## 核心组件分析 + +### JobConfigurationBuilder接口 +JobConfigurationBuilder是作业配置构建的核心接口,定义了配置构建的标准流程。该接口采用SPI(Service Provider Interface)机制,允许不同引擎实现各自的配置构建逻辑。 + +```mermaid +classDiagram +class JobConfigurationBuilder { +<> ++init(Map, JobExecutionInfo) void ++buildName() void ++buildEnvConfig() void ++buildSourceConfigs() void ++buildTransformConfigs() void ++buildSinkConfigs() void ++build() DataVinesJobConfig +} +class BaseJobConfigurationBuilder { +-configuration DataVinesJobConfig +-inputParameter Map +-jobExecutionParameter JobExecutionParameter +-jobExecutionInfo JobExecutionInfo +-metric2InputParameter Map> ++init(Map, JobExecutionInfo) void ++buildName() void ++buildEnvConfig() void ++buildSourceConfigs() void ++buildTransformConfigs() void ++buildSinkConfigs() void ++build() DataVinesJobConfig +#getEnvConfig() EnvConfig +#getSourceConfigs() List +#getMetricUniqueKey(BaseJobParameter) String +} +JobConfigurationBuilder <|-- BaseJobConfigurationBuilder +``` + +**图表来源** +- [JobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java#L27-L42) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L45-L321) + +**本节来源** +- [JobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java#L1-L43) + +### BaseJobConfigurationBuilder抽象类 +BaseJobConfigurationBuilder是JobConfigurationBuilder接口的抽象实现,提供了通用的配置构建能力。该类通过模板方法模式实现了配置构建的标准化流程,同时允许子类通过抽象方法提供特定实现。 + +该类的主要功能包括: +- 初始化输入参数和作业执行信息 +- 构建作业名称 +- 构建环境配置 +- 构建数据源配置 +- 构建转换配置 +- 构建目标配置 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Builder as "BaseJobConfigurationBuilder" +participant Plugin as "PluginLoader" +participant Metric as "SqlMetric" +Client->>Builder : init(inputParameter, jobExecutionInfo) +Builder->>Builder : 初始化输入参数 +Builder->>Builder : 设置时间相关参数 +Builder->>Builder : 处理错误数据存储参数 +Builder->>Builder : 处理验证结果数据存储参数 +Builder->>Builder : 为每个度量指标创建独立参数映射 +Client->>Builder : buildName() +Builder->>Builder : 设置作业名称 +Client->>Builder : buildEnvConfig() +Builder->>Builder : 调用getEnvConfig()抽象方法 +Client->>Builder : buildSourceConfigs() +Builder->>Builder : 调用getSourceConfigs()抽象方法 +Client->>Builder : buildTransformConfigs() +Builder->>Plugin : 加载SqlMetric插件 +Plugin-->>Builder : 返回SqlMetric实例 +Builder->>Metric : getInvalidateItems(inputParameter) +Metric-->>Builder : 返回无效项SQL +Builder->>Metric : getActualValue(inputParameter) +Metric-->>Builder : 返回实际值SQL +Builder->>Plugin : 加载ExpectedValue插件 +Plugin-->>Builder : 返回ExpectedValue实例 +Builder->>Builder : 生成预期值SQL +Client->>Builder : build() +Builder-->>Client : 返回DataVinesJobConfig +``` + +**图表来源** +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L45-L321) + +**本节来源** +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L1-L322) + +### MetricParserUtils工具类 +MetricParserUtils是度量指标解析的核心工具类,提供了参数处理、转换配置设置和唯一码生成等关键功能。 + +```mermaid +classDiagram +class MetricParserUtils { ++operateInputParameter(Map, SqlMetric, JobExecutionInfo) void ++setTransformerConfig(Map, List, ExecuteSql, String) void ++generateUniqueCode(Map) String ++getOnClause(List, Map, boolean) String ++getWhereClause(List, Map, boolean) String ++getColumnIsNullStr(String, List, boolean) String +} +class BaseJobConfigurationBuilder { +-metric2InputParameter Map> +} +BaseJobConfigurationBuilder --> MetricParserUtils : "使用" +``` + +**图表来源** +- [MetricParserUtils.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/MetricParserUtils.java#L43-L223) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L55-L56) + +**本节来源** +- [MetricParserUtils.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/MetricParserUtils.java#L1-L223) + +## 配置构建流程 + +### 完整配置构建流程 +作业配置构建系统遵循标准化的构建流程,将高层业务逻辑转换为可执行的底层配置。该流程包括参数初始化、配置构建和最终配置生成三个主要阶段。 + +```mermaid +flowchart TD +Start([开始]) --> Init["初始化参数"] +Init --> SetTime["设置时间相关参数"] +SetTime --> SetErrorData["设置错误数据存储参数"] +SetErrorData --> SetValidateResult["设置验证结果数据存储参数"] +SetValidateResult --> BuildName["构建作业名称"] +BuildName --> BuildEnv["构建环境配置"] +BuildEnv --> BuildSource["构建数据源配置"] +BuildSource --> BuildTransform["构建转换配置"] +BuildTransform --> BuildSink["构建目标配置"] +BuildSink --> Validate["验证配置"] +Validate --> End([返回DataVinesJobConfig]) +subgraph "转换配置构建细节" +BuildTransform --> LoadMetric["加载SqlMetric插件"] +LoadMetric --> GetInvalidate["获取无效项SQL"] +GetInvalidate --> SetInvalidate["设置无效项转换配置"] +SetInvalidate --> GetActual["获取实际值SQL"] +GetActual --> SetActual["设置实际值转换配置"] +SetActual --> LoadExpected["加载ExpectedValue插件"] +LoadExpected --> GetExpected["获取预期值SQL"] +GetExpected --> SetExpected["设置预期值转换配置"] +end +``` + +**图表来源** +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L58-L219) + +**本节来源** +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L1-L322) + +## 参数验证与默认值填充 + +### 参数初始化与处理 +在配置构建过程中,系统会自动处理参数验证和默认值填充,确保配置的完整性和正确性。 + +```mermaid +flowchart TD +Start([参数初始化]) --> CheckTime["检查时间参数"] +CheckTime --> |DATA_TIME为空| SetNow["设置当前时间"] +CheckTime --> |DATA_TIME不为空| KeepOriginal["保持原值"] +SetNow --> CheckDate["检查日期参数"] +KeepOriginal --> CheckDate +CheckDate --> |DATA_DATE为空| SetToday["设置今天日期"] +CheckDate --> |DATA_DATE不为空| KeepDate["保持原值"] +SetToday --> HandleRegexp["处理正则表达式"] +KeepDate --> HandleRegexp +HandleRegexp --> EscapePattern["转义正则表达式模式"] +EscapePattern --> PrepareMetric["调用SqlMetric.prepare()"] +PrepareMetric --> End([完成参数处理]) +``` + +**图表来源** +- [MetricParserUtils.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/MetricParserUtils.java#L45-L74) + +**本节来源** +- [MetricParserUtils.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/MetricParserUtils.java#L1-L223) + +## 配置优化机制 + +### 唯一码生成算法 +系统通过generateUniqueCode方法生成唯一码,用于标识相同类型和条件的任务统计值,实现配置优化和缓存。 + +```mermaid +flowchart TD +Start([生成唯一码]) --> CheckInput["检查输入参数"] +CheckInput --> |参数为空| ReturnMinus1["返回-1"] +CheckInput --> |参数不为空| CreateMap["创建新参数映射"] +CreateMap --> AddMetricName["添加度量名称"] +AddMetricName --> AddDatabase["添加数据库名"] +AddDatabase --> LoadMetric["加载SqlMetric插件"] +LoadMetric --> GetConfigMap["获取配置映射"] +GetConfigMap --> |配置映射不为空| IterateConfig["遍历配置项"] +IterateConfig --> CheckValue["检查参数值"] +CheckValue --> |值不为空| AddToMap["添加到新映射"] +AddToMap --> NextConfig["下一个配置项"] +NextConfig --> |还有配置项| CheckValue +NextConfig --> |无更多配置项| BuildString["构建字符串"] +BuildString --> ConcatValues["连接所有值"] +ConcatValues --> GenerateMD5["生成MD5哈希"] +GenerateMD5 --> ReturnCode["返回8位MD5码"] +ReturnMinus1 --> End([结束]) +ReturnCode --> End +``` + +**图表来源** +- [MetricParserUtils.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/MetricParserUtils.java#L119-L143) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L313-L319) + +**本节来源** +- [MetricParserUtils.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/MetricParserUtils.java#L1-L223) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L1-L322) + +## 自定义配置构建器开发指南 + +### 创建自定义配置构建器 +开发者可以通过继承BaseJobConfigurationBuilder类来创建自定义的配置构建器,实现特定引擎或场景的配置构建逻辑。 + +```mermaid +classDiagram +class JobConfigurationBuilder { +<> +} +class BaseJobConfigurationBuilder { +<> +} +class CustomJobConfigurationBuilder { ++getEnvConfig() EnvConfig ++getSourceConfigs() List +} +JobConfigurationBuilder <|-- BaseJobConfigurationBuilder +BaseJobConfigurationBuilder <|-- CustomJobConfigurationBuilder +``` + +**开发步骤:** +1. 创建新类继承BaseJobConfigurationBuilder +2. 实现getEnvConfig()抽象方法 +3. 实现getSourceConfigs()抽象方法 +4. 在META-INF/plugins目录下注册SPI服务 + +**本节来源** +- [JobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java#L27-L42) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L45-L321) + +## 最佳实践 + +### 配置构建最佳实践 +在开发和使用作业配置构建系统时,应遵循以下最佳实践: + +1. **参数命名规范**:使用统一的参数命名约定,避免命名冲突 +2. **错误处理**:在构建过程中妥善处理异常情况 +3. **性能优化**:合理使用缓存机制,避免重复计算 +4. **扩展性设计**:遵循开闭原则,便于系统扩展 +5. **配置验证**:在构建完成后进行完整的配置验证 + +### 插件开发最佳实践 +1. **接口隔离**:确保插件接口职责单一 +2. **版本兼容**:保持向后兼容性 +3. **文档完整**:提供详细的插件文档 +4. **测试覆盖**:确保充分的测试覆盖 +5. **性能监控**:添加必要的性能监控点 + +## 结论 +作业配置构建系统通过清晰的接口定义、灵活的抽象基类和强大的工具类,实现了从高层业务逻辑到底层执行配置的高效转换。该系统不仅提供了标准化的配置构建流程,还通过SPI机制支持灵活的扩展,为不同引擎和场景提供了统一的配置管理方案。通过遵循本文档中的指南和最佳实践,开发者可以有效地利用和扩展该系统,满足多样化的数据质量检测需求。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/Component\346\216\245\345\217\243.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/Component\346\216\245\345\217\243.md" new file mode 100644 index 00000000..9083152c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/Component\346\216\245\345\217\243.md" @@ -0,0 +1,218 @@ +# Component接口 + + +**本文档中引用的文件** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [LocalSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalSource.java) +- [LocalSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalSink.java) +- [BaseJdbcSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSource.java) +- [BaseJdbcSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSink.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + + +## 目录 +1. [介绍](#介绍) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 介绍 +Component接口是DataVines数据处理流水线中的核心抽象,为数据源、转换器和接收器等组件提供了统一的插件化扩展机制。该接口定义了组件的生命周期方法,并通过SPI机制实现了灵活的插件加载。本文档深入解析Component接口的设计原理、实现方式及其在构建数据处理流水线中的关键作用。 + +## 核心组件 +Component接口作为DataVines系统中所有可插拔组件的基础,通过继承Plugin接口并结合SPI注解,实现了组件的动态发现和加载。该接口定义了prepare方法,用于在组件执行前进行必要的初始化工作。基于Component接口,系统构建了LocalSource和LocalSink等具体接口,分别代表数据源和数据接收器,为不同类型的数据处理组件提供了统一的抽象。 + +**Section sources** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [LocalSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalSource.java) +- [LocalSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalSink.java) + +## 架构概述 +```mermaid +classDiagram +class Component { +<> ++prepare(env) void +} +class Plugin { +<> +} +class LocalSource { +<> ++getConnectionItem(env) ConnectionHolder ++checkTableExist() boolean +} +class LocalSink { +<> ++output(resultList, env) void ++setExceptedValue(config, resultList, inputParameter) void +} +class BaseJdbcSource { +-config Config +-connectionHolder ConnectionHolder ++setConfig(config) void ++getConfig() Config ++checkConfig() CheckResult ++prepare(env) void ++getConnectionItem(env) ConnectionHolder ++checkTableExist() boolean +} +class BaseJdbcSink { +-config Config +-log Logger ++setConfig(config) void ++getConfig() Config ++checkConfig() CheckResult ++prepare(env) void ++output(resultList, env) void ++getExecutionResultTableSql() String ++getActualValueTableSql() String ++getProfileValueTableSql() String +} +Component <|-- LocalSource +Component <|-- LocalSink +Plugin <|-- Component +LocalSource <|-- BaseJdbcSource +LocalSink <|-- BaseJdbcSink +``` + +**Diagram sources** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [LocalSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalSource.java) +- [LocalSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalSink.java) +- [BaseJdbcSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSource.java) +- [BaseJdbcSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSink.java) + +## 详细组件分析 + +### Component接口分析 +Component接口是DataVines系统中所有可插拔组件的基础接口,它继承自Plugin接口并被@SPI注解标记,表明这是一个服务提供者接口,可以通过SPI机制进行动态加载。该接口定义了prepare方法,用于在组件执行前进行必要的环境准备和初始化工作。 + +```mermaid +classDiagram +class Component { +<> ++prepare(env) void +} +class SPI { +<> ++value() String +} +class Plugin { +<> +} +Component <|-- Plugin +Component ..>> SPI : 注解 +``` + +**Diagram sources** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) + +**Section sources** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) + +### 数据源组件分析 +LocalSource接口扩展了Component接口,定义了数据源组件的特定行为。BaseJdbcSource作为JDBC数据源的基类实现,提供了连接管理、配置验证和表存在性检查等功能。该实现通过ConnectionHolder封装数据库连接,并利用ConnectorFactory和JdbcUtils进行数据库操作。 + +```mermaid +sequenceDiagram +participant User as 用户 +participant BaseJdbcSource as BaseJdbcSource +participant ConnectionHolder as ConnectionHolder +participant ConnectorFactory as ConnectorFactory +participant JdbcUtils as JdbcUtils +User->>BaseJdbcSource : getConnectionItem(env) +BaseJdbcSource->>ConnectionHolder : 创建或获取连接 +BaseJdbcSource->>ConnectorFactory : getOrCreatePlugin(type) +ConnectorFactory-->>BaseJdbcSource : 返回ConnectorFactory实例 +BaseJdbcSource->>JdbcUtils : tableExists(connection, options, dialect) +JdbcUtils-->>BaseJdbcSource : 返回表存在性结果 +BaseJdbcSource-->>User : 返回ConnectionHolder +``` + +**Diagram sources** +- [BaseJdbcSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSource.java) +- [ConnectionHolder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/entity/ConnectionHolder.java) +- [ConnectorFactory.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) +- [JdbcUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/JdbcUtils.java) + +**Section sources** +- [BaseJdbcSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSource.java) + +### 数据接收器组件分析 +LocalSink接口扩展了Component接口,定义了数据接收器组件的特定行为。BaseJdbcSink作为JDBC接收器的基类实现,提供了多种类型数据的输出功能,包括验证结果、实际值、配置文件值等。该实现通过策略模式根据配置的插件类型选择相应的执行器进行数据写入。 + +```mermaid +flowchart TD +Start([output方法调用]) --> CreateInput["创建输入参数Map"] +CreateInput --> SetExpected["调用setExceptedValue设置期望值"] +SetExpected --> DetermineType["根据PLUGIN_TYPE确定接收器类型"] +DetermineType --> CheckType{类型判断} +CheckType --> |ERROR_DATA| CreateErrorExecutor["创建ErrorDataSinkExecutor"] +CheckType --> |VALIDATE_RESULT| CreateValidateExecutor["创建ValidateResultDataSinkExecutor"] +CheckType --> |ACTUAL_VALUE| CreateActualExecutor["创建ActualValueDataSinkExecutor"] +CheckType --> |PROFILE_VALUE| CreateProfileExecutor["创建ProfileDataSinkExecutor"] +CreateErrorExecutor --> ExecuteError["执行execute方法"] +CreateValidateExecutor --> ExecuteValidate["执行execute方法"] +CreateActualExecutor --> ExecuteActual["执行execute方法"] +CreateProfileExecutor --> ExecuteProfile["执行execute方法"] +ExecuteError --> End([方法结束]) +ExecuteValidate --> End +ExecuteActual --> End +ExecuteProfile --> End +``` + +**Diagram sources** +- [BaseJdbcSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSink.java) +- [ISinkExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/executor/ISinkExecutor.java) + +**Section sources** +- [BaseJdbcSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSink.java) + +## 依赖分析 +```mermaid +graph TD +Component --> Plugin +Component --> SPI +LocalSource --> Component +LocalSink --> Component +BaseJdbcSource --> LocalSource +BaseJdbcSource --> ConnectionHolder +BaseJdbcSource --> ConnectorFactory +BaseJdbcSource --> JdbcUtils +BaseJdbcSink --> LocalSink +BaseJdbcSink --> ISinkExecutor +PluginLoader --> SPI +PluginLoader --> Component +BaseJdbcSource --> PluginLoader +``` + +**Diagram sources** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +**Section sources** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +## 性能考虑 +Component接口的设计充分考虑了性能因素。通过SPI机制实现的插件延迟加载避免了不必要的类加载开销。BaseJdbcSource中的连接池管理和重试机制确保了数据库连接的稳定性和可靠性。BaseJdbcSink中的策略模式避免了重复的对象创建,提高了执行效率。建议在实际使用中合理配置连接池参数和重试次数,以平衡性能和可靠性。 + +## 故障排除指南 +当遇到Component接口相关的问题时,首先检查SPI配置文件是否正确放置在META-INF/services目录下。确认插件实现类的全限定名是否正确写入配置文件。对于数据库连接问题,检查BaseJdbcSource中的连接参数配置是否正确,并确保数据库驱动已正确添加到类路径。对于数据写入问题,验证BaseJdbcSink中的表结构SQL是否与目标数据库兼容。 + +**Section sources** +- [BaseJdbcSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSource.java) +- [BaseJdbcSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSink.java) + +## 结论 +Component接口作为DataVines系统的核心抽象,成功实现了数据处理组件的统一管理和插件化扩展。通过继承Component接口并结合SPI机制,开发者可以轻松创建自定义的数据源和接收器组件。BaseJdbcSource和BaseJdbcSink的实现为JDBC相关的组件开发提供了优秀的参考模板。该设计模式不仅提高了系统的可扩展性,还保证了代码的可维护性和可测试性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/EngineConstants\345\270\270\351\207\217\347\261\273.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/EngineConstants\345\270\270\351\207\217\347\261\273.md" new file mode 100644 index 00000000..2bc6662b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/EngineConstants\345\270\270\351\207\217\347\261\273.md" @@ -0,0 +1,116 @@ +# EngineConstants常量类 + + +**本文档引用的文件** +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java#L1-L33) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java#L32-L34) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L169-L177) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java#L31-L32) +- [SparkBatchExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/batch/SparkBatchExecution.java#L31-L32) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java#L37-L38) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java#L107-L109) + + +## 目录 +1. [简介](#简介) +2. [常量定义与用途](#常量定义与用途) +3. [在引擎配置中的作用](#在引擎配置中的作用) +4. [在状态管理中的应用](#在状态管理中的应用) +5. [在通信协议中的角色](#在通信协议中的角色) +6. [使用最佳实践与注意事项](#使用最佳实践与注意事项) +7. [自定义扩展中的引用方式](#自定义扩展中的引用方式) +8. [总结](#总结) + +## 简介 + +`EngineConstants` 是 DataVines 引擎模块中定义的一个核心常量类,位于 `io.datavines.engine.api` 包下。该类集中管理了引擎运行时所需的关键配置项键名、状态标识和通用参数名称,为不同执行引擎(如 Spark、Flink、Local 等)提供统一的配置接口。通过使用这些常量,系统实现了配置解析、组件通信和运行时环境构建的标准化,增强了代码的可维护性和可扩展性。 + +该类主要包含五类常量:表名相关常量(用于数据流中输入、输出和临时表的命名)、进程标识常量(用于获取和管理执行进程ID)、插件类型常量(用于区分不同类型的插件组件)以及类型标识常量(用于指定执行模式或组件类型)。这些常量贯穿于引擎的配置解析、任务执行和资源管理等核心流程中。 + +## 常量定义与用途 + +`EngineConstants` 类中定义的常量均为 `public static final` 类型,确保其在整个应用生命周期内不可变且全局可访问。以下是各常量的详细说明: + +- **OUTPUT_TABLE ("output_table")**: 用于指定数据处理组件(如 Source、Transform)的输出结果表名。在 Spark 和 Flink 引擎中,此常量对应的配置值会被注册为临时视图,供后续组件查询使用。 +- **INPUT_TABLE ("input_table")**: 用于指定数据处理组件的输入数据源表名。组件通过该配置项获取上游组件生成的临时表或已注册的视图名称,实现数据流的串联。 +- **TMP_TABLE ("tmp_table")**: 用于指定临时表名称,通常用于中间计算结果的存储。与 `OUTPUT_TABLE` 不同,`TMP_TABLE` 更强调其临时性和中间状态,可能在任务结束后被清理。 +- **PID ("pid")**: 用于反射获取 Java `Process` 对象的进程ID字段。该常量在进程管理和任务取消功能中起关键作用,允许系统通过操作系统命令(如 `kill`)直接终止执行中的任务进程。 +- **PLUGIN_TYPE ("plugin_type")**: 用于标识插件组件的类型。在运行时,系统通过读取配置中的 `plugin_type` 值,结合枚举类(如 `SourceType`、`SinkType`)进行类型判断,从而决定组件的执行逻辑和数据流向。 +- **TYPE ("type")**: 用于指定执行环境或组件的类型。例如,在 Flink 引擎中,该常量用于区分 `batch` 和 `stream` 两种执行模式,从而配置不同的运行时参数。 + +**本节来源** +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java#L21-L32) + +## 在引擎配置中的作用 + +`EngineConstants` 在引擎配置解析过程中扮演着核心角色。以 `ConfigParser` 类为例,该类负责将 JSON 格式的作业配置转换为运行时对象。在解析过程中,`PLUGIN_TYPE` 和 `TYPE` 常量被频繁使用,以确保配置项的正确映射。 + +当解析数据源(Source)、接收器(Sink)和转换器(Transform)的配置时,`ConfigParser` 会将每个组件的 `type` 字段值通过 `PLUGIN_TYPE` 常量注入到其配置对象中。这使得插件在初始化时能够准确识别自身的类型,并据此加载相应的处理逻辑。例如,在 `getSourcePlugins` 方法中,`sinkConfig.getConfig().put(PLUGIN_TYPE, sinkConfig.getType());` 这行代码确保了每个 Sink 插件都能通过 `PLUGIN_TYPE` 获取到其类型信息。 + +此外,`TYPE` 常量被用于配置运行时环境。`ConfigParser` 在创建 `RuntimeEnvironment` 时,会将 `envConfig.getType()` 的值通过 `TYPE` 键存入环境配置中。这样,Flink 或 Spark 等具体引擎在准备运行时环境时,就可以通过 `config.getString(TYPE)` 来判断当前是批处理还是流处理模式,并相应地配置执行参数。 + +**本节来源** +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java#L32-L34) +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java#L29-L31) + +## 在状态管理中的应用 + +`EngineConstants` 中的常量在任务的状态管理和进程控制中发挥着重要作用。最典型的例子是 `PID` 常量在 `BaseCommandProcess` 类中的应用。 + +`BaseCommandProcess` 是一个抽象基类,用于管理通过命令行启动的外部进程。为了实现对进程的精确控制(如取消或终止),系统需要获取进程的原生操作系统进程ID(PID)。由于 Java 标准库的 `Process` 类没有提供直接获取 PID 的公共方法,因此采用了反射技术。`getProcessId(Process process)` 方法通过 `process.getClass().getDeclaredField(EngineConstants.PID)` 反射访问 `Process` 对象的私有 `pid` 字段,从而获取到真实的进程ID。 + +获取到 PID 后,系统可以执行 `softKill(pid)` 或 `hardKill(pid)` 操作,分别对应 `kill` 和 `kill -9` 命令,实现对任务进程的优雅关闭或强制终止。这种机制对于保证任务调度系统的稳定性和资源回收的及时性至关重要。 + +**本节来源** +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L169-L177) + +## 在通信协议中的角色 + +`EngineConstants` 定义的常量作为不同组件间通信的“协议”或“契约”,确保了数据在不同模块间传递时的一致性和可理解性。这些常量充当了配置键的标准化词汇表,避免了因键名拼写错误或不一致而导致的配置解析失败。 + +例如,在 `LocalExecution` 类中,`PLUGIN_TYPE` 常量被用于 `switch` 语句来判断 `LocalSource`、`LocalTransform` 和 `LocalSink` 组件的具体类型。代码 `SourceType.of(localSource.getConfig().getString(PLUGIN_TYPE))` 通过读取配置中的 `plugin_type` 值,精确地确定了数据源是 `SOURCE`、`TARGET` 还是 `METADATA`,并执行相应的连接和数据校验逻辑。这种基于常量的类型分发机制,使得代码结构清晰,易于扩展新的数据源类型。 + +同样,在 `SparkBatchExecution` 类中,`INPUT_TABLE` 和 `OUTPUT_TABLE` 常量定义了数据流的“连接点”。一个组件通过 `OUTPUT_TABLE` 将其结果注册为临时视图,而下一个组件则通过 `INPUT_TABLE` 配置来引用这个视图。这种约定俗成的通信方式,使得数据处理流水线的构建变得简单而可靠。 + +**本节来源** +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java#L37-L38) +- [SparkBatchExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/batch/SparkBatchExecution.java#L31-L32) + +## 使用最佳实践与注意事项 + +在使用 `EngineConstants` 类时,应遵循以下最佳实践: + +1. **始终使用常量而非字面量**:在代码中引用配置键时,必须使用 `EngineConstants` 中定义的常量,如 `config.getString(EngineConstants.OUTPUT_TABLE)`,而不是直接使用字符串 `"output_table"`。这可以防止拼写错误,并在常量需要修改时只需更改一处。 +2. **理解常量的上下文**:不同的常量适用于不同的场景。例如,`TYPE` 通常用于区分执行模式(batch/stream),而 `PLUGIN_TYPE` 用于区分插件的业务类型(如 source/sink)。在使用时应确保语义正确。 +3. **避免常量污染**:不应在 `EngineConstants` 类中随意添加新的常量。只有那些被多个模块广泛使用、具有全局意义的配置键才应被提升为常量。特定于某个模块的配置键应定义在该模块的内部。 +4. **与枚举类配合使用**:`PLUGIN_TYPE` 的值通常与枚举类(如 `SourceType`、`SinkType`)的名称相对应。在定义枚举时,应确保其 `toString()` 或 `name()` 方法返回的字符串与配置中使用的值一致。 + +**注意事项**: +- `PID` 常量的使用依赖于 Java 内部实现,不同 JDK 版本或不同操作系统下 `Process` 类的字段名可能不同,存在一定的兼容性风险。 +- 所有常量均为字符串,使用时需注意大小写敏感性,建议在配置文件中统一使用小写。 + +**本节来源** +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java#L21-L32) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java#L107-L109) + +## 自定义扩展中的引用方式 + +在开发自定义的引擎插件(如新的 Source、Sink 或 Transform)时,正确引用 `EngineConstants` 是确保插件能被系统正确识别和执行的关键。 + +1. **配置解析**:在插件的 `setConfig` 方法中,应使用 `EngineConstants` 中的常量来读取配置。例如,一个自定义的 Sink 插件应通过 `config.getString(EngineConstants.INPUT_TABLE)` 来获取其输入数据表名。 +2. **类型注册**:如果插件需要根据 `PLUGIN_TYPE` 进行逻辑分支,应在代码中使用 `SinkType.of(config.getString(EngineConstants.PLUGIN_TYPE))` 这样的方式来解析类型,而不是直接比较字符串。 +3. **依赖声明**:在插件的 `pom.xml` 文件中,必须声明对 `datavines-engine-api` 模块的依赖,以便能够访问 `EngineConstants` 类。 +4. **常量复用**:如果自定义插件需要定义新的配置项,应优先考虑是否可以复用 `EngineConstants` 或 `ConfigConstants` 中已有的常量,以保持系统的一致性。 + +通过遵循这些规范,可以确保自定义扩展与核心引擎的无缝集成。 + +**本节来源** +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java#L21-L32) +- [SparkBatchExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/batch/SparkBatchExecution.java#L74-L76) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java#L64-L65) + +## 总结 + +`EngineConstants` 类是 DataVines 引擎架构中的一个基础性组件,它通过集中管理核心配置键,为整个系统的配置、通信和状态管理提供了坚实的基础。通过对 `OUTPUT_TABLE`、`INPUT_TABLE`、`PID`、`PLUGIN_TYPE` 和 `TYPE` 等常量的分析,我们可以看到它们在数据流定义、进程控制、类型分发和模块通信中所起的关键作用。 + +正确理解和使用这些常量,不仅能够提高代码的健壮性和可维护性,还能确保自定义扩展与核心系统的兼容性。在开发和维护过程中,应始终遵循使用常量的最佳实践,避免硬编码,从而构建一个更加稳定和可扩展的数据质量引擎。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/EngineExecutor\346\216\245\345\217\243.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/EngineExecutor\346\216\245\345\217\243.md" new file mode 100644 index 00000000..015c36bf --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/EngineExecutor\346\216\245\345\217\243.md" @@ -0,0 +1,235 @@ +# EngineExecutor接口 + + +**本文档引用的文件** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [MetricController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/MetricController.java) + + +## 目录 +1. [引言](#引言) +2. [核心方法详解](#核心方法详解) +3. [接口设计与执行流程](#接口设计与执行流程) +4. [不同执行引擎的实现方式](#不同执行引擎的实现方式) +5. [使用示例与最佳实践](#使用示例与最佳实践) +6. [自定义引擎实现指导](#自定义引擎实现指导) +7. [结论](#结论) + +## 引言 +EngineExecutor接口是DataVines数据质量框架中的核心接口,定义了任务执行的契约。该接口为不同的计算引擎(如Spark、Flink等)提供了统一的执行抽象,使得系统能够灵活地支持多种执行引擎。通过SPI机制,系统可以动态加载和管理不同的引擎实现。 + +**Section sources** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L26-L42) + +## 核心方法详解 + +### 初始化方法 (init) +`init`方法用于初始化执行器,接收任务执行请求、日志记录器和配置信息作为参数。该方法在任务执行前被调用,负责设置执行环境和准备必要的资源。 + +**Section sources** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L28-L28) + +### 执行方法 (execute) +`execute`方法是核心的执行方法,负责启动任务的实际执行。该方法会阻塞直到任务完成或被取消。在不同的引擎实现中,该方法的具体实现会有所不同,但都遵循相同的执行契约。 + +**Section sources** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L30-L30) + +### 后处理方法 (after) +`after`方法在任务执行完成后调用,用于执行清理工作和资源释放。无论任务成功还是失败,该方法都会被执行,确保资源的正确回收。 + +**Section sources** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L32-L32) + +### 取消方法 (cancel) +`cancel`方法用于取消正在执行的任务。该方法会尝试终止任务的执行,并设置取消标志。不同的引擎实现会根据其特性提供相应的取消机制。 + +**Section sources** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L34-L34) + +### 取消状态检查 (isCancel) +`isCancel`方法用于检查任务是否已被取消。返回布尔值表示当前任务的取消状态,这对于在执行过程中检查取消请求非常重要。 + +**Section sources** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L36-L36) + +### 获取处理结果 (getProcessResult) +`getProcessResult`方法返回任务执行的结果信息,包括退出状态码、进程ID、应用ID等。这些信息对于监控任务状态和故障排查至关重要。 + +**Section sources** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L38-L38) + +### 获取任务请求 (getTaskRequest) +`getTaskRequest`方法返回与执行器关联的任务执行请求对象,包含任务的详细配置和参数信息。 + +**Section sources** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L40-L40) + +## 接口设计与执行流程 + +```mermaid +sequenceDiagram +participant JobRunner as JobRunner +participant EngineExecutor as EngineExecutor +participant SparkExecutor as SparkEngineExecutor +participant FlinkExecutor as FlinkEngineExecutor +JobRunner->>EngineExecutor : getPluginLoader(EngineExecutor.class) +JobRunner->>EngineExecutor : getNewPlugin(engineType) +JobRunner->>EngineExecutor : init(request, logger, config) +JobRunner->>EngineExecutor : execute() +alt 任务成功 +EngineExecutor-->>JobRunner : 返回成功状态 +else 任务失败 +EngineExecutor-->>JobRunner : 返回失败状态 +end +JobRunner->>EngineExecutor : after() +JobRunner->>EngineExecutor : getProcessResult() +``` + +**Diagram sources** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L73-L79) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L28-L40) + +### 抽象基类设计 +`AbstractEngineExecutor`作为所有具体实现的基类,提供了公共的字段和方法实现,包括取消状态管理和日志处理。这种设计模式遵循了模板方法模式,确保了执行流程的一致性。 + +```mermaid +classDiagram +class EngineExecutor { +<> ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++after() ++cancel() ++isCancel() ++getProcessResult() ++getTaskRequest() +} +class AbstractEngineExecutor { +-JobExecutionRequest jobExecutionRequest +-Logger logger +-volatile boolean cancel +-ProcessResult processResult ++logHandle(String[]) ++isCancel() ++buildCommand() +} +class SparkEngineExecutor { ++init() ++execute() ++after() ++cancel() ++getProcessResult() +} +class FlinkEngineExecutor { ++init() ++execute() ++after() ++cancel() ++getProcessResult() +} +EngineExecutor <|-- AbstractEngineExecutor +AbstractEngineExecutor <|-- SparkEngineExecutor +AbstractEngineExecutor <|-- FlinkEngineExecutor +``` + +**Diagram sources** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L26-L42) + +## 不同执行引擎的实现方式 + +### Spark引擎实现 +SparkEngineExecutor实现了基于Spark的执行逻辑,通过构建适当的命令行参数来启动Spark应用。该实现支持YARN和本地模式等多种部署方式。 + +**Section sources** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) + +### Flink引擎实现 +FlinkEngineExecutor提供了Flink任务的执行支持,能够通过命令行或REST API与Flink集群交互。该实现特别关注流处理任务的执行和管理。 + +**Section sources** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) + +### Livy引擎实现 +LivyEngineExecutor通过Livy服务与Spark集群交互,提供了更高级别的REST API抽象。这种实现方式特别适合在多租户环境中运行Spark作业。 + +**Section sources** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) + +### 本地引擎实现 +LocalEngineExecutor提供了在本地执行任务的能力,主要用于开发和测试场景。该实现直接在当前JVM中执行任务逻辑。 + +**Section sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) + +## 使用示例与最佳实践 + +### 任务执行流程 +```mermaid +flowchart TD +Start([开始]) --> Init["初始化执行器"] +Init --> Execute["执行任务"] +Execute --> CheckCancel{"是否取消?"} +CheckCancel --> |是| Cancel["执行取消逻辑"] +CheckCancel --> |否| CheckStatus{"执行完成?"} +CheckStatus --> |否| Execute +CheckStatus --> |是| After["执行后处理"] +After --> GetResult["获取执行结果"] +GetResult --> End([结束]) +Cancel --> After +``` + +**Diagram sources** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L77-L79) + +### SPI机制集成 +系统通过SPI机制动态加载引擎实现,`MetricController`中的`getEngineTypeList`方法展示了如何获取所有支持的引擎类型: + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Controller as MetricController +participant PluginLoader as PluginLoader +Client->>Controller : GET /api/engine/list +Controller->>PluginLoader : getPluginLoader(EngineExecutor.class) +PluginLoader-->>Controller : 返回插件加载器 +Controller->>PluginLoader : getSupportedPlugins() +PluginLoader-->>Controller : 返回支持的引擎列表 +Controller->>Client : 返回引擎类型列表 +``` + +**Diagram sources** +- [MetricController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/MetricController.java#L194-L198) + +## 自定义引擎实现指导 + +### 实现步骤 +1. 创建新的Maven模块作为插件 +2. 实现EngineExecutor接口 +3. 在resources/META-INF/plugins/目录下创建配置文件 +4. 注册SPI实现 + +### 配置文件示例 +在`resources/META-INF/plugins/io.datavines.engine.api.engine.EngineExecutor`文件中添加: +``` +myengine=com.example.MyCustomEngineExecutor +``` + +### 注意事项 +- 确保实现类有默认构造函数 +- 正确处理异常情况 +- 实现资源清理逻辑 +- 支持取消操作 + +**Section sources** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L26-L42) + +## 结论 +EngineExecutor接口通过清晰的契约定义和灵活的SPI机制,为DataVines框架提供了强大的执行引擎抽象能力。这种设计不仅支持现有的Spark、Flink等主流计算引擎,还为未来扩展新的执行引擎提供了便利。通过统一的执行接口,系统能够轻松地在不同计算平台之间切换,满足多样化的数据处理需求。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/RuntimeEnvironment\346\216\245\345\217\243.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/RuntimeEnvironment\346\216\245\345\217\243.md" new file mode 100644 index 00000000..b9edf5a6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/RuntimeEnvironment\346\216\245\345\217\243.md" @@ -0,0 +1,277 @@ +# RuntimeEnvironment接口 + + +**本文档中引用的文件** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) +- [SparkBatchExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/batch/SparkBatchExecution.java) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + + +## 目录 +1. [简介](#简介) +2. [接口定义](#接口定义) +3. [核心方法解析](#核心方法解析) +4. [执行环境实现](#执行环境实现) +5. [执行上下文管理](#执行上下文管理) +6. [使用示例](#使用示例) +7. [扩展指导](#扩展指导) +8. [架构图](#架构图) + +## 简介 +RuntimeEnvironment接口是DataVines引擎的核心组件之一,用于封装不同执行环境(如Yarn、Livy、Local)的上下文信息和配置参数。该接口通过抽象化不同执行平台的细节,为上层应用提供统一的执行环境管理能力。通过实现该接口,可以支持多种执行环境,包括本地执行、Spark执行和Flink执行等。 + +**Section sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) + +## 接口定义 +RuntimeEnvironment接口定义了执行环境的基本契约,继承自Plugin接口并使用@SPI注解标记,表明它是一个可扩展的SPI(Service Provider Interface)接口。该接口主要包含两个核心方法:prepare()和getExecution()。 + +```mermaid +classDiagram +class RuntimeEnvironment { +<> ++prepare() void ++getExecution() Execution +} +class Plugin { +<> ++setConfig(Config) void ++getConfig() Config ++checkConfig() CheckResult +} +RuntimeEnvironment --|> Plugin +``` + +**Diagram sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) + +**Section sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) + +## 核心方法解析 +RuntimeEnvironment接口定义了两个关键方法,用于环境初始化和执行上下文获取。 + +### prepare方法 +prepare方法负责执行环境的初始化工作,包括资源配置、连接建立和环境配置等。不同的实现类会根据具体的执行平台进行相应的初始化操作。 + +### getExecution方法 +getExecution方法返回与当前运行时环境关联的Execution实例,该实例负责具体的任务执行逻辑。Execution接口定义了execute、stop和prepare等方法,用于控制任务的执行流程。 + +```mermaid +classDiagram +class RuntimeEnvironment { +<> ++prepare() void ++getExecution() Execution +} +class Execution { +<> ++execute(SR[], TF[], SK[]) void ++stop() void ++prepare() void +} +RuntimeEnvironment ..> Execution : "返回" +``` + +**Diagram sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + +**Section sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + +## 执行环境实现 +DataVines提供了多种RuntimeEnvironment的实现,以支持不同的执行平台。 + +### LocalRuntimeEnvironment +LocalRuntimeEnvironment是本地执行环境的实现,主要用于在本地JVM中执行任务。它管理本地数据库连接和执行状态。 + +```mermaid +classDiagram +class LocalRuntimeEnvironment { +-sourceConnection ConnectionHolder +-targetConnection ConnectionHolder +-metadataConnection ConnectionHolder +-currentStatement Statement +-stop boolean ++prepare() void ++getExecution() Execution ++close() void +} +class ConnectionHolder { +-connection Connection +-close() void +} +LocalRuntimeEnvironment --> ConnectionHolder : "包含" +LocalRuntimeEnvironment --|> RuntimeEnvironment +``` + +**Diagram sources** +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) + +**Section sources** +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) + +### SparkRuntimeEnvironment +SparkRuntimeEnvironment是Spark执行环境的实现,用于在Spark集群上执行任务。它管理SparkSession和StreamingContext等Spark核心组件。 + +```mermaid +classDiagram +class SparkRuntimeEnvironment { +-sparkSession SparkSession +-streamingContext StreamingContext +-config Config +-enableSparkHiveSupport boolean ++prepare() void ++getExecution() Execution ++sparkSession() SparkSession ++streamingContext() StreamingContext +} +SparkRuntimeEnvironment --|> RuntimeEnvironment +``` + +**Diagram sources** +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) + +**Section sources** +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) + +### FlinkRuntimeEnvironment +FlinkRuntimeEnvironment是Flink执行环境的实现,用于在Flink集群上执行流处理任务。它管理StreamExecutionEnvironment和StreamTableEnvironment等Flink核心组件。 + +```mermaid +classDiagram +class FlinkRuntimeEnvironment { +-env StreamExecutionEnvironment +-tableEnv StreamTableEnvironment +-config Config ++prepare() void ++getExecution() Execution ++stop() void +} +FlinkRuntimeEnvironment --|> RuntimeEnvironment +``` + +**Diagram sources** +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) + +**Section sources** +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) + +## 执行上下文管理 +RuntimeEnvironment通过Execution接口管理具体的执行上下文。不同的执行环境实现会返回相应的Execution实例。 + +### 执行流程 +```mermaid +sequenceDiagram +participant Bootstrap as BaseDataVinesBootstrap +participant RuntimeEnv as RuntimeEnvironment +participant Execution as Execution +participant Components as Components +Bootstrap->>RuntimeEnv : getExecution() +RuntimeEnv-->>Bootstrap : 返回Execution实例 +Bootstrap->>Execution : prepare() +Bootstrap->>Components : prepare(RuntimeEnvironment) +Bootstrap->>Execution : execute(sources, transforms, sinks) +Execution->>Execution : 执行任务流程 +Execution-->>Bootstrap : 执行完成 +Bootstrap->>Execution : stop() +``` + +**Diagram sources** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + +**Section sources** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +## 使用示例 +以下是一个典型的RuntimeEnvironment使用示例: + +```mermaid +flowchart TD +Start([开始]) --> CreateRuntime["创建RuntimeEnvironment实例"] +CreateRuntime --> SetConfig["设置配置参数"] +SetConfig --> Prepare["调用prepare()初始化环境"] +Prepare --> GetExecution["调用getExecution()获取执行器"] +GetExecution --> Execute["执行任务"] +Execute --> Stop["停止执行环境"] +Stop --> End([结束]) +``` + +**Diagram sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) + +**Section sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) + +## 扩展指导 +要创建自定义的执行环境,需要实现RuntimeEnvironment接口并遵循以下步骤: + +1. 创建新的实现类,继承RuntimeEnvironment接口 +2. 实现prepare()方法进行环境初始化 +3. 实现getExecution()方法返回相应的Execution实例 +4. 在META-INF/plugins目录下创建服务发现文件 + +```mermaid +classDiagram +class CustomRuntimeEnvironment { +-customResource CustomResource +-config Config ++prepare() void ++getExecution() Execution +} +CustomRuntimeEnvironment --|> RuntimeEnvironment +CustomRuntimeEnvironment --> CustomExecution : "返回" +``` + +**Diagram sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) + +**Section sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) + +## 架构图 +以下是RuntimeEnvironment的整体架构: + +```mermaid +graph TD +subgraph "执行环境实现" +Local[LocalRuntimeEnvironment] +Spark[SparkRuntimeEnvironment] +Flink[FlinkRuntimeEnvironment] +Custom[CustomRuntimeEnvironment] +end +subgraph "核心接口" +RuntimeEnv[RuntimeEnvironment] +Execution[Execution] +end +subgraph "执行组件" +Sources[数据源组件] +Transforms[转换组件] +Sinks[输出组件] +end +RuntimeEnv --> |实现| Local +RuntimeEnv --> |实现| Spark +RuntimeEnv --> |实现| Flink +RuntimeEnv --> |实现| Custom +RuntimeEnv --> |返回| Execution +Execution --> |执行| Sources +Execution --> |执行| Transforms +Execution --> |执行| Sinks +``` + +**Diagram sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + +**Section sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241.md" new file mode 100644 index 00000000..0187a7cc --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241/\345\274\225\346\223\216API\344\270\216\346\212\275\350\261\241.md" @@ -0,0 +1,260 @@ +# 引擎API与抽象 + + +**本文档中引用的文件** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [io.datavines.engine.api.engine.EngineExecutor](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/resources/META-INF/plugins/io.datavines.engine.api.engine.EngineExecutor) +- [io.datavines.engine.api.env.RuntimeEnvironment](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/resources/META-INF/plugins/io.datavines.engine.api.env.RuntimeEnvironment) + + +## 目录 +1. [引言](#引言) +2. [核心接口定义](#核心接口定义) +3. [执行契约详解](#执行契约详解) +4. [运行时环境封装](#运行时环境封装) +5. [执行流水线构建](#执行流水线构建) +6. [常量定义与使用](#常量定义与使用) +7. [SPI扩展机制](#spi扩展机制) +8. [实现示例分析](#实现示例分析) +9. [架构关系图](#架构关系图) +10. [结论](#结论) + +## 引言 +DataVines引擎API与抽象层为数据质量检测系统提供了统一的执行框架。该框架通过定义清晰的接口契约,实现了不同执行引擎之间的解耦,支持本地、Spark、Flink等多种执行环境。本文档深入解析引擎API的核心组件,包括执行契约、运行时环境、流水线构建等关键概念,以及SPI扩展机制的实现原理。 + +## 核心接口定义 +引擎API的核心由多个接口组成,这些接口共同构成了执行引擎的基础架构。主要接口包括EngineExecutor、RuntimeEnvironment、Component和Plugin,它们通过继承关系和组合模式构建了一个灵活可扩展的执行框架。 + +```mermaid +classDiagram +class EngineExecutor { +<> ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++isCancel() boolean ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest +} +class RuntimeEnvironment { +<> ++prepare() void ++getExecution() Execution +} +class Component { +<> ++prepare(RuntimeEnvironment) void +} +class Plugin { +<> ++setConfig(Config) void ++getConfig() Config ++checkConfig() CheckResult +} +class Execution { +<> ++execute(SR[], TF[], SK[]) void ++stop() void ++prepare() void +} +EngineExecutor <|-- AbstractEngineExecutor +AbstractEngineExecutor <|-- LocalEngineExecutor +RuntimeEnvironment <|-- LocalRuntimeEnvironment +RuntimeEnvironment --> Execution +Component <|-- JdbcSource +Component <|-- SqlTransform +Component <|-- JdbcSink +Plugin <|-- RuntimeEnvironment +Plugin <|-- Component +Plugin <|-- EngineExecutor +``` + +**图表来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java#L23-L28) +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java#L24-L26) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java#L24-L31) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java#L23-L30) + +## 执行契约详解 +EngineExecutor接口定义了执行引擎的核心契约,规范了任务执行的完整生命周期。该接口通过一系列方法调用,确保了执行过程的标准化和可预测性。 + +### 初始化方法 +init方法负责执行器的初始化工作,接收任务执行请求、日志记录器和配置信息作为参数。这是执行流程的起点,为后续的执行做好准备。 + +### 执行方法 +execute方法是执行器的核心,负责启动实际的任务执行过程。该方法被设计为阻塞调用,直到任务完成或被取消。 + +### 清理方法 +after方法在执行完成后调用,用于执行必要的清理工作,如资源释放、状态更新等。 + +### 取消机制 +cancel方法提供了任务取消的能力,isCancel方法则用于查询当前任务是否已被取消,两者共同实现了执行过程的可控性。 + +### 结果获取 +getProcessResult方法返回执行结果,getTaskRequest方法返回原始的任务请求,这两个方法为执行结果的获取和追溯提供了支持。 + +**章节来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L27-L42) + +## 运行时环境封装 +RuntimeEnvironment接口封装了不同执行环境的上下文信息,为执行过程提供了必要的环境支持。 + +### 环境准备 +prepare方法负责环境的准备工作,如连接建立、资源分配等。该方法在执行开始前调用,确保执行环境处于就绪状态。 + +### 执行获取 +getExecution方法返回与当前环境关联的执行实例,实现了环境与执行的绑定。通过这种方式,不同的运行时环境可以提供不同的执行策略。 + +### 插件继承 +RuntimeEnvironment继承自Plugin接口,获得了配置管理能力。这使得运行时环境可以接收外部配置,并进行有效性验证。 + +**章节来源** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java#L23-L28) + +## 执行流水线构建 +Component接口在构建执行流水线中扮演着关键角色,它定义了流水线中各个组件的基本行为。 + +### 组件准备 +prepare方法接收RuntimeEnvironment作为参数,允许组件根据当前执行环境进行初始化和配置。这种设计使得组件能够适应不同的执行环境。 + +### 流水线结构 +执行流水线通常由三个部分组成:数据源(Source)、数据转换(Transform)和数据接收器(Sink)。每个部分都实现了Component接口,形成了统一的处理流程。 + +### 类型参数化 +Execution接口使用泛型参数SR、TF、SK分别表示源、转换和接收器类型,提供了类型安全的执行契约。这种设计既保证了类型安全,又保持了足够的灵活性。 + +**章节来源** +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java#L24-L26) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java#L23-L30) + +## 常量定义与使用 +EngineConstants类定义了引擎API中使用的各类常量,为配置和数据交换提供了统一的标准。 + +### 表名常量 +OUTPUT_TABLE、INPUT_TABLE和TMP_TABLE常量用于标识不同类型的数据表,确保在数据处理过程中表名的一致性。 + +### 标识常量 +PID常量用于标识进程ID,在分布式环境中用于跟踪和管理执行实例。 + +### 类型常量 +PLUGIN_TYPE和TYPE常量用于标识插件类型和组件类型,支持基于类型的插件查找和实例化。 + +这些常量的集中定义避免了代码中的魔法值,提高了代码的可读性和可维护性。 + +**章节来源** +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java#L19-L32) + +## SPI扩展机制 +SPI(Service Provider Interface)机制是引擎API实现可扩展性的核心,它允许在不修改核心代码的情况下添加新的功能实现。 + +### 注解定义 +@SPI注解标记了可扩展的接口,表明这些接口的实现可以通过SPI机制动态加载。该注解位于datavines-spi模块中,为整个系统提供了统一的扩展点管理。 + +### 插件加载 +PluginLoader类负责SPI插件的加载和管理。它通过读取META-INF/plugins目录下的配置文件,发现并实例化插件实现。 + +### 配置文件 +插件配置文件位于META-INF/plugins目录下,文件名是接口的全限定名,内容是实现类的别名和全限定名映射。例如,EngineExecutor的配置文件定义了local别名对应的LocalEngineExecutor实现。 + +### 动态实例化 +PluginLoader提供了getOrCreatePlugin方法,根据别名获取或创建插件实例。该方法实现了单例模式,确保相同别名的插件在系统中只有一个实例。 + +**章节来源** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L28-L32) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L51-L487) +- [io.datavines.engine.api.engine.EngineExecutor](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/resources/META-INF/plugins/io.datavines.engine.api.engine.EngineExecutor#L1) +- [io.datavines.engine.api.env.RuntimeEnvironment](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/resources/META-INF/plugins/io.datavines.engine.api.env.RuntimeEnvironment#L1) + +## 实现示例分析 +以本地执行引擎为例,分析核心接口的具体实现方式。 + +### 执行器实现 +LocalEngineExecutor继承自AbstractEngineExecutor,实现了EngineExecutor接口。它通过LocalDataVinesBootstrap启动本地执行流程,并管理执行状态。 + +### 环境实现 +LocalRuntimeEnvironment实现了RuntimeEnvironment接口,提供了本地执行环境的具体实现。它管理数据库连接、执行状态等运行时信息。 + +### 抽象基类 +AbstractEngineExecutor提供了执行器的公共实现,如取消标志、日志处理等,减少了重复代码,提高了代码复用性。 + +这些实现展示了如何通过继承和组合模式,构建一个完整且可扩展的执行引擎。 + +**章节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L27-L57) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java#L32-L98) + +## 架构关系图 +以下图表展示了引擎API各组件之间的关系和交互流程。 + +```mermaid +graph TD +subgraph "核心接口" +A[EngineExecutor] +B[RuntimeEnvironment] +C[Component] +D[Plugin] +end +subgraph "SPI机制" +E[SPI注解] +F[PluginLoader] +G[插件配置文件] +end +subgraph "实现类" +H[LocalEngineExecutor] +I[LocalRuntimeEnvironment] +J[AbstractEngineExecutor] +end +A --> |继承| J +J --> |实现| H +B --> |实现| I +B --> C +C --> |具体实现| 数据源 +C --> |具体实现| 转换器 +C --> |具体实现| 接收器 +D --> A +D --> B +D --> C +E --> A +E --> B +E --> C +F --> G +G --> H +G --> I +style A fill:#f9f,stroke:#333 +style B fill:#f9f,stroke:#333 +style C fill:#f9f,stroke:#333 +style D fill:#f9f,stroke:#333 +style E fill:#bbf,stroke:#333 +style F fill:#bbf,stroke:#333 +style G fill:#bbf,stroke:#333 +style H fill:#9ff,stroke:#333 +style I fill:#9ff,stroke:#333 +style J fill:#9ff,stroke:#333 +``` + +**图表来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) + +## 结论 +DataVines引擎API与抽象层通过精心设计的接口契约和SPI扩展机制,构建了一个灵活、可扩展的执行框架。EngineExecutor接口定义了统一的执行契约,RuntimeEnvironment封装了执行环境的上下文信息,Component接口支持构建复杂的执行流水线,而SPI机制则为系统的可扩展性提供了坚实的基础。这种设计不仅支持当前的本地、Spark、Flink等执行引擎,也为未来添加新的执行引擎提供了便利,体现了良好的架构设计原则。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/Livy\346\211\247\350\241\214\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/Livy\346\211\247\350\241\214\345\231\250.md" new file mode 100644 index 00000000..2be025c0 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/Livy\346\211\247\350\241\214\345\231\250.md" @@ -0,0 +1,258 @@ +# Livy执行器 + + +**本文档引用的文件** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) +- [LivySparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\LivySparkParameters.java) +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractYarnEngineExecutor.java) +- [YarnUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\YarnUtils.java) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) +- [common.properties](file://datavines-common\src\main\resources\common.properties) + + +## 目录 +1. [简介](#简介) +2. [核心架构](#核心架构) +3. [会话管理与作业提交](#会话管理与作业提交) +4. [资源调度策略](#资源调度策略) +5. [容错与恢复机制](#容错与恢复机制) +6. [作业参数构造与请求封装](#作业参数构造与请求封装) +7. [性能对比与适用场景](#性能对比与适用场景) +8. [配置参数详解](#配置参数详解) + +## 简介 + +Livy执行器是DataVines平台中用于与Apache Livy服务器交互的关键组件,它通过REST API实现Spark作业的远程提交和状态监控。该执行器基于`AbstractLivyEngineExecutor`抽象类构建,通过`LivyTaskSubmitHelper`辅助类处理与Livy服务器的HTTP通信。Livy执行器的主要优势在于它能够以会话(session)的方式管理Spark作业,提供更细粒度的控制和更好的资源隔离。与传统的Yarn执行器相比,Livy执行器通过REST API与Livy服务器通信,而Livy服务器再与Yarn资源管理器交互,这种间接的架构提供了更好的安全性和多租户支持。 + +**本节来源** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java#L1-L37) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L1-L237) + +## 核心架构 + +Livy执行器的架构采用分层设计,各组件职责明确,协同工作完成Spark作业的提交和监控。核心组件包括`LivyEngineExecutor`、`LivyCommandProcess`、`LivyTaskSubmitHelper`和`LivySparkParameters`。`LivyEngineExecutor`作为具体的执行器实现,继承自`AbstractLivyEngineExecutor`,负责初始化和协调整个作业执行流程。`LivyCommandProcess`负责处理与Livy服务器的通信细节,包括提交作业、查询状态和取消作业。`LivyTaskSubmitHelper`则封装了REST API调用的底层逻辑,支持Kerberos认证等高级功能。`LivySparkParameters`类定义了提交Spark作业所需的所有参数。 + +```mermaid +classDiagram +class AbstractEngineExecutor { ++JobExecutionRequest jobExecutionRequest ++Logger logger ++ProcessResult processResult ++boolean cancel ++logHandle(String[] logs) ++isCancel() boolean ++buildCommand() String +} +class AbstractLivyEngineExecutor { ++LivyCommandProcess livyCommandProcess ++cancel() void +} +class LivyEngineExecutor { ++Configurations configurations ++init(JobExecutionRequest, Logger, Configurations) ++execute() void ++buildCommand() String +} +class LivyCommandProcess { ++LivyTaskSubmitHelper livyTaskSubmitHelper ++int appIdRetryCount ++post2LivyWithRetry(String livyArgs) Map~String, Object~ ++processResultOfLivyState(Object sessionId, ProcessResult processResult) boolean ++cancel() void +} +class LivyTaskSubmitHelper { ++RestTemplate restTemplate ++String uri ++Configurations configurations ++init() void ++postToLivy(String livyArgs) String ++getFromLivy(String uri) String ++deleteByLivy(Long sessionId, String appId) void ++retryLivyGetAppId(String result, int appIdRetryCount) Map~String, Object~ +} +class LivySparkParameters { ++String className ++Integer executorCores ++String driverMemory ++Integer numExecutors ++Integer driverCores ++String executorMemory ++String name ++String queue ++String proxyUser ++String file ++String[] args ++String[] jars ++Map~String, Object~ conf +} +AbstractEngineExecutor <|-- AbstractLivyEngineExecutor +AbstractLivyEngineExecutor <|-- LivyEngineExecutor +LivyEngineExecutor --> LivyCommandProcess +LivyCommandProcess --> LivyTaskSubmitHelper +LivyEngineExecutor --> LivySparkParameters +``` + +**图示来源** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java#L23-L36) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L42-L236) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L38-L142) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) +- [LivySparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\LivySparkParameters.java#L22-L193) + +## 会话管理与作业提交 + +Livy执行器通过REST API与Livy服务器交互,实现Spark作业的会话管理和远程提交。作业提交流程始于`LivyEngineExecutor`的`execute`方法,该方法调用`LivyCommandProcess`的`post2LivyWithRetry`方法提交作业。`LivyCommandProcess`首先通过`buildCommand`方法构造符合Livy API要求的JSON请求体,然后使用`LivyTaskSubmitHelper`的`postToLivy`方法发送POST请求到Livy服务器的`/batches`端点。成功提交后,Livy服务器返回一个包含会话ID的响应,执行器通过轮询`/batches/{sessionId}`端点来监控作业状态。 + +```mermaid +sequenceDiagram +participant LivyEngineExecutor as Livy执行器 +participant LivyCommandProcess as 命令处理器 +participant LivyTaskSubmitHelper as 提交助手 +participant LivyServer as Livy服务器 +LivyEngineExecutor->>LivyCommandProcess : execute() +LivyCommandProcess->>LivyEngineExecutor : buildCommand() +LivyEngineExecutor-->>LivyCommandProcess : JSON请求体 +LivyCommandProcess->>LivyTaskSubmitHelper : post2LivyWithRetry() +LivyTaskSubmitHelper->>LivyServer : POST /batches +LivyServer-->>LivyTaskSubmitHelper : 201 Created + 会话ID +LivyTaskSubmitHelper-->>LivyCommandProcess : 返回结果 +loop 状态监控 +LivyCommandProcess->>LivyTaskSubmitHelper : getResultByLivyId() +LivyTaskSubmitHelper->>LivyServer : GET /batches/{sessionId} +LivyServer-->>LivyTaskSubmitHelper : 会话状态 +LivyTaskSubmitHelper-->>LivyCommandProcess : 状态信息 +alt 作业成功 +LivyCommandProcess->>LivyEngineExecutor : 设置成功状态 +break 结束 +else 作业失败或被取消 +LivyCommandProcess->>LivyEngineExecutor : 设置失败状态 +break 结束 +else 作业仍在运行 +LivyCommandProcess->>LivyCommandProcess : 等待1秒 +end +end +``` + +**图示来源** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L60-L78) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L71-L119) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L113-L164) + +**本节来源** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L60-L78) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L71-L119) + +## 资源调度策略 + +Livy执行器的资源调度策略主要通过配置参数来实现,这些参数在`LivySparkParameters`类中定义,并在`LivyEngineExecutor`的`buildCommand`方法中设置。执行器支持配置驱动程序和执行器的内存、核心数、队列等资源。资源调度平台类型由`ResourceSchedulePlatformType`枚举定义,目前支持YARN。执行器通过读取配置文件中的`livy.uri`参数确定Livy服务器地址,并通过`livy.task.proxyUser`参数支持代理用户提交作业,这对于多租户环境非常重要。资源调度的粒度由`numExecutors`、`executorCores`和`executorMemory`等参数控制,允许用户根据作业需求精确分配资源。 + +**本节来源** +- [LivySparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\LivySparkParameters.java#L22-L193) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L97-L236) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) + +## 容错与恢复机制 + +Livy执行器实现了多层次的容错与恢复机制,确保作业的可靠执行。状态监控方面,`LivyCommandProcess`的`processResultOfLivyState`方法通过轮询Livy服务器获取会话状态,使用`LivyStates`枚举来解析和判断状态。当检测到`DEAD`、`ERROR`、`KILLED`或`UNKNOWN`状态时,执行器会将作业标记为失败。取消机制方面,`cancel`方法首先调用Livy服务器的DELETE接口终止会话,如果失败则回退到直接调用Yarn的`application -kill`命令。此外,`retryLivyGetAppId`方法实现了获取应用ID的重试逻辑,通过配置`livy.task.appId.retry.count`参数控制重试次数,默认为2次。 + +```mermaid +flowchart TD +Start([开始状态监控]) --> GetStatus["调用LivyTaskSubmitHelper.getResultByLivyId()"] +GetStatus --> CheckResult{"结果是否为空?"} +CheckResult --> |是| SetFailure["设置失败状态"] +CheckResult --> |否| ParseState["调用LivyStates.toLivyState()解析状态"] +ParseState --> CheckState{"状态是否为SUCCESS?"} +CheckState --> |是| SetSuccess["设置成功状态"] +CheckState --> |否| CheckError{"状态是否为DEAD/ERROR/KILLED/UNKNOWN?"} +CheckError --> |是| SetFailure +CheckError --> |否| Wait["等待1秒"] +Wait --> GetStatus +SetSuccess --> End([结束]) +SetFailure --> End +``` + +**图示来源** +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L87-L119) +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java#L24-L82) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L67-L103) + +**本节来源** +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L87-L119) +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java#L24-L82) + +## 作业参数构造与请求封装 + +作业参数的构造和请求封装是通过`LivyEngineExecutor`的`buildCommand`方法和`LivyTaskSubmitHelper`类协同完成的。`buildCommand`方法首先从`JobExecutionRequest`中解析出`SparkParameters`,然后将其转换为`LivySparkParameters`对象。这个过程包括设置主类、JAR文件路径、依赖JAR包、作业参数和配置项。`LivyTaskSubmitHelper`负责将构造好的参数对象序列化为JSON字符串,并通过HTTP POST请求发送到Livy服务器。该类还处理了Kerberos认证,根据`livy.need.kerberos`配置决定使用普通`RestTemplate`还是`KerberosRestTemplate`。 + +```mermaid +flowchart TD +A([开始构建命令]) --> B["解析JobExecutionRequest.getEngineParameter()"] +B --> C["创建LivySparkParameters实例"] +C --> D["设置className, driverMemory等参数"] +D --> E["设置主JAR文件路径"] +E --> F["设置依赖JAR包列表"] +F --> G["设置作业参数DataVinesJobConfig"] +G --> H["设置Spark配置conf"] +H --> I["序列化为JSON字符串"] +I --> J["返回JSON命令"] +``` + +**图示来源** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L97-L157) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L113-L164) + +**本节来源** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L97-L157) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L113-L164) + +## 性能对比与适用场景 + +与Yarn执行器相比,Livy执行器在性能和适用场景上有显著差异。Yarn执行器通过`ShellCommandProcess`直接执行`spark-submit`命令,通信开销小,启动速度快,适合对延迟敏感的场景。而Livy执行器通过REST API与Livy服务器通信,增加了网络开销和中间层处理时间,但提供了更好的安全性和多租户支持。Livy执行器适用于需要细粒度权限控制、动态资源分配和Web友好的交互环境。在容错方面,Livy执行器的状态监控更稳定,因为Livy服务器会持久化会话状态,即使客户端断开连接,作业仍可继续运行。然而,Yarn执行器在资源利用率上可能更高,因为它直接与Yarn交互,减少了中间层的资源消耗。 + +```mermaid +graph TD +subgraph "Livy执行器" +A[优点] +B[缺点] +A --> A1[更好的安全性] +A --> A2[多租户支持] +A --> A3[会话持久化] +A --> A4[REST API友好] +B --> B1[更高的延迟] +B --> B2[额外的资源开销] +B --> B3[依赖Livy服务] +end +subgraph "Yarn执行器" +C[优点] +D[缺点] +C --> C1[更低的延迟] +C --> C2[更高的资源利用率] +C --> C3[直接控制] +D --> D1[安全性较低] +D --> D2[多租户支持弱] +D --> D3[无会话持久化] +end +``` + +**图示来源** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractYarnEngineExecutor.java) +- [YarnUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\YarnUtils.java) + +**本节来源** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractYarnEngineExecutor.java) +- [YarnUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\YarnUtils.java) + +## 配置参数详解 + +Livy执行器的行为由一系列配置参数控制,这些参数主要定义在`application.yaml`和`common.properties`文件中。关键配置包括`livy.uri`(Livy服务器地址)、`livy.need.kerberos`(是否启用Kerberos认证)、`livy.task.jar.lib.path`(JAR包库路径)和`livy.task.proxyUser`(代理用户)。`livy.task.appId.retry.count`参数控制获取应用ID的重试次数,对于网络不稳定的环境尤为重要。`livy.server.auth.kerberos.principal`和`livy.server.auth.kerberos.keytab`用于配置Kerberos认证的凭据。这些配置使得Livy执行器能够适应不同的部署环境和安全要求。 + +**本节来源** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) +- [common.properties](file://datavines-common\src\main\resources\common.properties) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L53-L65) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/Yarn\346\211\247\350\241\214\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/Yarn\346\211\247\350\241\214\345\231\250.md" new file mode 100644 index 00000000..5de4e11d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/Yarn\346\211\247\350\241\214\345\231\250.md" @@ -0,0 +1,259 @@ +# Yarn执行器 + + +**本文档中引用的文件** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) + + +## 目录 +1. [引言](#引言) +2. [Yarn执行器架构](#yarn执行器架构) +3. [核心组件分析](#核心组件分析) +4. [资源隔离与队列管理](#资源隔离与队列管理) +5. [Yarn与Livy执行器对比](#yarn与livy执行器对比) +6. [大规模集群性能优化](#大规模集群性能优化) +7. [故障恢复机制](#故障恢复机制) +8. [配置建议](#配置建议) +9. [结论](#结论) + +## 引言 +Yarn执行器是DataVines平台中用于与Hadoop Yarn资源管理器直接交互的核心组件,负责作业的资源申请和任务调度。该执行器通过抽象基类`AbstractYarnEngineExecutor`实现与Yarn ResourceManager的通信,支持在大规模分布式环境中高效执行数据质量检查任务。本文档将深入分析Yarn执行器的实现机制,包括资源隔离、队列管理和优先级调度等关键功能,并与Livy执行器进行对比,提供在大规模集群环境中的性能优化建议。 + +## Yarn执行器架构 + +```mermaid +classDiagram +class AbstractEngineExecutor { ++JobExecutionRequest jobExecutionRequest ++Logger logger ++Configurations configurations ++boolean cancel ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++cancel() ++getResult() +} +class AbstractYarnEngineExecutor { +-ShellCommandProcess shellCommandProcess ++cancel() +-killYarnApplication() +} +class FlinkEngineExecutor { +-Configurations configurations +-BaseCommandProcess shellCommandProcess ++init(JobExecutionRequest, Logger, Configurations) ++execute() +} +class YarnUtils { +-String YARN_MODE_KEY +-String YARN_RESOURCE_MANAGER_HA_IDS_KEY +-String YARN_APPLICATION_STATUS_ADDRESS_KEY ++getApplicationUrl(String) ++getActiveResourceManagerName(String) ++getResourceManagerState(String) ++getYarnAppId(String, String) ++getApplicationStatus(String) ++isSuccessOfYarnState(String) +} +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +AbstractYarnEngineExecutor <|-- FlinkEngineExecutor +FlinkEngineExecutor --> YarnUtils : "使用" +AbstractYarnEngineExecutor --> YarnUtils : "使用" +``` + +**图表来源** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) + +**本节来源** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L59) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L29-L270) + +## 核心组件分析 + +### AbstractYarnEngineExecutor实现机制 +`AbstractYarnEngineExecutor`作为Yarn执行器的抽象基类,定义了与Yarn ResourceManager交互的核心机制。该类通过继承`AbstractEngineExecutor`并扩展Yarn特定功能,实现了作业的生命周期管理。当需要取消作业时,执行器首先调用`shellCommandProcess.cancel()`终止本地进程,然后通过`killYarnApplication()`方法向Yarn集群发送应用终止指令。 + +作业取消流程通过`sudo -u {tenantCode} yarn application -kill {applicationId}`命令实现,该命令以租户用户身份执行,确保了多租户环境下的安全隔离。`YarnUtils`工具类负责获取应用ID,通过租户代码和作业执行唯一标识符进行查询,实现了精确的应用定位。 + +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant 执行器 as AbstractYarnEngineExecutor +participant Shell命令 as ShellCommandProcess +participant YarnUtils as YarnUtils +participant ResourceManager as Yarn ResourceManager +用户->>执行器 : cancel() +执行器->>Shell命令 : cancel() +执行器->>YarnUtils : getYarnAppId(tenantCode, jobExecutionUniqueId) +YarnUtils-->>执行器 : applicationId +执行器->>ResourceManager : yarn application -kill applicationId +ResourceManager-->>执行器 : 终止确认 +执行器-->>用户 : 取消完成 +``` + +**图表来源** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L30-L58) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L171-L191) + +**本节来源** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L59) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L171-L191) + +## 资源隔离与队列管理 + +### 资源隔离机制 +Yarn执行器通过多层机制实现资源隔离。首先,`ResourceSchedulePlatformType`枚举定义了三种资源调度平台类型:LOCAL、YARN和K8S,为不同环境提供了统一的抽象接口。在Yarn模式下,系统通过`yarn.mode`配置项确定部署模式,支持`none`、`ha`(高可用)和`standalone`三种模式。 + +高可用模式下,`getActiveResourceManagerName`方法通过HTTP接口查询ResourceManager状态,自动识别活跃的ResourceManager节点。该方法向`http://{rmId}:8088/ws/v1/cluster/info`发送请求,解析返回的JSON数据中的`haState`字段,当状态为`ACTIVE`时返回对应的ResourceManager ID,确保了在集群故障切换时仍能正确通信。 + +```mermaid +flowchart TD +Start([开始]) --> CheckMode["检查yarn.mode配置"] +CheckMode --> ModeDecision{"模式选择"} +ModeDecision --> |none| DisableYarn["禁用Yarn功能"] +ModeDecision --> |ha| HAEnabled["启用ResourceManager HA"] +ModeDecision --> |standalone| Standalone["启用单节点ResourceManager"] +HAEnabled --> GetActiveRM["获取活跃ResourceManager"] +GetActiveRM --> QueryRM1["查询RM1状态"] +QueryRM1 --> RM1Active{"RM1是否活跃?"} +RM1Active --> |是| ReturnRM1["返回RM1"] +RM1Active --> |否| QueryRM2["查询RM2状态"] +QueryRM2 --> RM2Active{"RM2是否活跃?"} +RM2Active --> |是| ReturnRM2["返回RM2"] +RM2Active --> |否| ReturnNull["返回空"] +ReturnRM1 --> End([结束]) +ReturnRM2 --> End +ReturnNull --> End +Standalone --> UseConfiguredAddress["使用配置的地址"] +UseConfiguredAddress --> End +DisableYarn --> End +``` + +**图表来源** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L59-L119) + +**本节来源** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L33-L151) +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java#L19-L25) + +### 队列管理与优先级调度 +Yarn执行器通过队列配置实现资源的分组管理和优先级调度。在Spark和Flink等具体执行器中,`queue`参数用于指定YARN队列,将作业提交到特定的资源池。这种机制允许多个团队或项目共享同一集群,同时保证关键任务获得足够的资源。 + +对于Flink作业,`FlinkArgsUtils`工具类在构建执行参数时,会根据部署模式添加相应的队列配置。当部署模式为YARN相关模式时,系统会添加`-Dyarn.application.queue={queueName}`参数,确保作业被正确分配到指定队列。此外,还可以通过`-Dyarn.tags`参数为作业添加标签,便于后续的监控和管理。 + +资源调度优先级通过YARN自身的容量调度器或公平调度器实现。管理员可以配置队列的容量、最大容量和权重,控制不同队列之间的资源分配比例。执行器本身不直接管理优先级,而是通过选择适当的队列来间接影响作业的调度优先级。 + +**本节来源** +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java#L73-L75) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L79-L83) + +## Yarn与Livy执行器对比 + +### 部署复杂度对比 +Yarn执行器和Livy执行器在部署复杂度上存在显著差异。Yarn执行器直接与Yarn ResourceManager交互,只需要在执行节点配置好Hadoop客户端环境,包括`HADOOP_CONF_DIR`和相关配置文件。这种直接集成方式减少了中间件依赖,部署相对简单。 + +相比之下,Livy执行器需要额外部署Livy服务器,这是一个独立的REST服务,作为Spark和客户端之间的桥梁。Livy服务器需要与Spark集群紧密集成,配置Spark Home路径、Hadoop配置等。这种架构增加了系统组件数量,提高了部署和维护的复杂度。 + +```mermaid +graph TD +subgraph "Yarn执行器架构" +Client1[DataVines客户端] +Executor1[Yarn执行器] +YarnRM1[Yarn ResourceManager] +Client1 --> Executor1 +Executor1 --> YarnRM1 +end +subgraph "Livy执行器架构" +Client2[DataVines客户端] +LivyServer[Livy服务器] +SparkCluster[Spark集群] +Client2 --> LivyServer +LivyServer --> SparkCluster +end +``` + +**图表来源** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) + +**本节来源** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/README.md#L1-L6) + +### 资源利用率与故障恢复 +在资源利用率方面,Yarn执行器通常具有更高的效率。由于直接与Yarn交互,减少了中间层的开销,资源申请和释放更加及时。Yarn执行器可以精确控制容器的生命周期,根据作业需求动态调整资源分配。 + +Livy执行器由于引入了额外的REST层,存在一定的性能开销。Livy服务器需要维护与Spark应用的会话状态,这可能导致资源释放延迟。然而,Livy提供了更好的会话管理和多租户支持,适合需要长时间运行交互式作业的场景。 + +故障恢复机制上,Yarn执行器依赖Yarn自身的容错能力。当作业失败时,Yarn会尝试在其他节点重新启动容器。DataVines通过`JobExecutionFailover`机制监控作业状态,当检测到作业失败时,会自动触发重试逻辑。 + +Livy执行器的故障恢复更加复杂,需要处理Livy服务器故障、会话丢失等多种情况。Livy提供了会话持久化功能,可以在服务器重启后恢复之前的会话状态,但这也增加了系统复杂性。 + +**本节来源** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java#L25-L27) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L119-L144) + +## 大规模集群性能优化 + +### 配置优化建议 +在大规模集群环境中,Yarn执行器的性能优化需要从多个方面考虑。首先,合理配置`yarn.resource.manager.ha.ids`参数,确保高可用性。在生产环境中,应配置至少两个ResourceManager节点,避免单点故障。 + +其次,优化`yarn.application.status.address`配置,使用负载均衡器或DNS轮询,避免对单个ResourceManager节点造成过大压力。同时,适当调整`yarn.resource.manager.http.address.port`,确保监控接口的可用性。 + +对于资源密集型作业,建议配置合理的队列策略。通过`queue`参数将不同优先级的作业分配到不同的队列,避免低优先级作业占用过多资源。可以创建多个队列,如`default`、`high-priority`和`low-priority`,并配置相应的容量和权重。 + +### 监控与调优 +启用Yarn应用状态监控,定期调用`getApplicationStatus`方法检查作业状态。为了避免频繁查询对ResourceManager造成压力,建议设置合理的轮询间隔,通常为10-30秒。同时,实现超时机制,防止作业长时间处于未知状态。 + +在多租户环境中,确保`tenantCode`的正确使用,避免权限越界。通过`sudo -u {tenantCode}`命令以租户身份执行操作,实现了安全的资源隔离。同时,监控每个租户的资源使用情况,防止个别租户过度占用集群资源。 + +对于长时间运行的作业,建议配置检查点机制,定期保存作业状态。这样即使作业失败,也可以从最近的检查点恢复,减少重复计算的开销。 + +**本节来源** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L37-L41) +- [common.properties](file://datavines-common/src/main/resources/common.properties#L18-L25) +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) + +## 故障恢复机制 +Yarn执行器的故障恢复机制主要依赖于Yarn平台自身的容错能力。当容器失败时,Yarn会自动尝试在其他节点重新启动。DataVines通过`YarnJobExecutionStatusChecker`定期检查作业状态,当检测到作业失败时,会触发重试逻辑。 + +`isSuccessOfYarnState`方法实现了作业状态的轮询检查,通过`Thread.sleep(CommonConstants.SLEEP_TIME_MILLIS)`实现间隔轮询,避免对ResourceManager造成过大压力。当作业状态为`FAILURE`或`KILL`时,返回`false`,触发故障恢复流程。 + +在集群级别,建议配置Yarn的自动故障转移机制,确保ResourceManager高可用。同时,配置NodeManager的健康检查,及时发现和隔离故障节点。对于关键作业,可以配置重试次数和重试间隔,提高作业的可靠性。 + +**本节来源** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L242-L266) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L119-L144) + +## 配置建议 +1. **高可用配置**:在生产环境中,必须配置`yarn.mode=ha`,并设置`yarn.resource.manager.ha.ids`为多个ResourceManager节点的ID,确保集群高可用。 + +2. **资源隔离**:为不同租户配置独立的Yarn队列,通过`queue`参数控制资源分配。避免所有作业都提交到默认队列,导致资源争用。 + +3. **监控优化**:合理设置状态查询间隔,避免频繁查询影响ResourceManager性能。建议轮询间隔不低于10秒。 + +4. **安全配置**:确保`sudo`命令的正确配置,限制执行权限,防止安全漏洞。定期审计租户权限,确保资源使用的合规性。 + +5. **日志管理**:配置详细的日志记录,特别是`getApplicationUrl`和`killYarnApplication`等关键操作,便于故障排查。 + +6. **性能调优**:根据作业类型和资源需求,合理配置`numExecutors`、`executorCores`和`executorMemory`等参数,避免资源浪费或不足。 + +**本节来源** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) + +## 结论 +Yarn执行器作为DataVines平台的核心组件,通过`AbstractYarnEngineExecutor`基类实现了与Yarn ResourceManager的直接交互,提供了高效的资源申请和任务调度能力。其架构设计充分考虑了多租户环境下的资源隔离和安全性,通过租户代码和sudo机制实现了安全的作业管理。 + +与Livy执行器相比,Yarn执行器具有部署简单、资源利用率高的优势,特别适合批处理作业场景。然而,Livy执行器在交互式作业和会话管理方面具有优势。在选择执行器时,应根据具体应用场景和需求进行权衡。 + +在大规模集群环境中,通过合理的队列管理、高可用配置和监控优化,可以充分发挥Yarn执行器的性能优势。未来可以进一步优化故障恢复机制,实现更智能的作业重试和资源调度策略。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/\345\221\275\344\273\244\346\211\247\350\241\214\345\244\204\347\220\206\345\231\250.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/\345\221\275\344\273\244\346\211\247\350\241\214\345\244\204\347\220\206\345\231\250.md" new file mode 100644 index 00000000..be292dc2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/\345\221\275\344\273\244\346\211\247\350\241\214\345\244\204\347\220\206\345\231\250.md" @@ -0,0 +1,430 @@ +# 命令执行处理器 + + +**本文引用的文件列表** +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java) +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java) +- [ProcessUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ProcessUtils.java) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [ProcessResult.java](file://datavines-common/src/main/java/io/datavines/common/entity/ProcessResult.java) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java) +- [LivyStates.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [组件详解](#组件详解) +6. [依赖关系分析](#依赖关系分析) +7. [性能与稳定性考量](#性能与稳定性考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) + +## 简介 +本文件围绕命令执行处理器进行系统化技术文档整理,重点剖析 BaseCommandProcess 如何封装底层命令执行逻辑,覆盖进程创建、输入输出流处理、日志缓存与刷新、软硬终止策略、Yarn 应用状态判定、异常捕获与错误传播等关键能力;同时说明 ShellCommandProcess 与 LivyCommandProcess 的差异化实现,以及它们与执行器核心的协作方式,确保作业执行过程的稳定性与可观测性。 + +## 项目结构 +命令执行处理器位于引擎执行模块中,采用抽象基类 + 具体实现的分层设计: +- 抽象基类:BaseCommandProcess 负责统一的进程生命周期管理、日志采集与缓冲、取消与终止、退出码与应用状态判定。 +- 具体实现: + - ShellCommandProcess:面向本地或容器内 sh/bash 环境,通过写入临时命令文件并以 sudo -u 指定租户用户执行。 + - LivyCommandProcess:面向远程 Livy 服务提交批任务,通过 LivyTaskSubmitHelper 与 Livy 交互,并轮询状态判断最终结果。 +- 工具与实体: + - ProcessUtils:构建可打印的命令行字符串,便于审计与调试。 + - YarnUtils:查询 Yarn 应用状态,辅助判定成功/失败。 + - JobExecutionRequest/ProcessResult:承载执行上下文与结果数据。 + - CoreConfig:日志缓冲与刷新的配置项来源。 + - LivyStates/LivyTaskSubmitHelper:Livy 会话状态枚举与 HTTP 交互辅助。 + +```mermaid +graph TB +subgraph "执行器核心" +Base["BaseCommandProcess
统一进程生命周期与日志处理"] +Sh["ShellCommandProcess
本地/容器 sh 执行"] +Ly["LivyCommandProcess
Livy 远程批任务"] +end +subgraph "工具与实体" +PU["ProcessUtils
命令行拼接"] +YU["YarnUtils
Yarn 应用状态"] +JER["JobExecutionRequest
执行请求上下文"] +PR["ProcessResult
执行结果"] +CC["CoreConfig
日志配置"] +LS["LivyStates
状态枚举"] +LTH["LivyTaskSubmitHelper
Livy HTTP 辅助"] +end +Base --> Sh +Base --> Ly +Base --> PU +Base --> YU +Base --> JER +Base --> PR +Base --> CC +Ly --> LS +Ly --> LTH +``` + +图表来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L1-L365) +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java#L1-L80) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L1-L143) +- [ProcessUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ProcessUtils.java#L1-L302) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L1-L270) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java#L1-L86) +- [ProcessResult.java](file://datavines-common/src/main/java/io/datavines/common/entity/ProcessResult.java#L1-L43) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java#L1-L41) +- [LivyStates.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java#L1-L83) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L1-L258) + +章节来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L1-L365) +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java#L1-L80) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L1-L143) + +## 核心组件 +- BaseCommandProcess + - 统一职责:进程启动、输出解析、日志缓冲与刷新、软硬终止、退出码与应用状态判定、取消流程。 + - 关键点: + - 使用 ProcessBuilder 启动进程,合并标准错误到标准输出,设置工作目录与用户(sudo -u 租户)。 + - 通过反射读取进程 PID,便于日志与终止操作。 + - 输出解析使用单线程守护线程池异步读取标准输出,按配置阈值批量刷新至上层日志处理器。 + - 取消流程:优先软杀(kill),失败则硬杀(kill -9),最后 destroy 进程并清理缓冲。 + - 退出码判定:非 Yarn 场景依据进程返回码;Yarn 场景通过 YarnUtils 查询最终状态决定成功/失败。 +- ShellCommandProcess + - 面向本地/容器 sh 环境,写入临时命令文件,注入执行目录、环境变量与实际命令,再以指定解释器执行。 +- LivyCommandProcess + - 面向远程 Livy 提交批任务,借助 LivyTaskSubmitHelper 完成提交、轮询、删除等操作,并根据 LivyStates 判定最终状态。 + +章节来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L81-L128) +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java#L43-L79) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L38-L142) + +## 架构总览 +下图展示从调用 run 到完成执行的关键流程,涵盖进程创建、输出解析、日志刷新、取消与退出码判定。 + +```mermaid +sequenceDiagram +participant Caller as "调用方" +participant Proc as "BaseCommandProcess" +participant PB as "ProcessBuilder" +participant ProcInst as "进程实例" +participant Out as "输出解析线程" +participant Yarn as "YarnUtils" +participant Log as "日志处理器" +Caller->>Proc : "run(executeCommand)" +Proc->>Proc : "buildCommandFilePath()
createCommandFileIfNotExists()" +Proc->>PB : "配置工作目录/合并错误流/设置命令" +PB-->>ProcInst : "start()" +Proc->>Proc : "parseProcessOutput(ProcInst)" +Proc->>Out : "异步读取标准输出" +Out->>Log : "按阈值批量刷新日志" +Proc->>ProcInst : "waitFor()" +Proc->>Yarn : "Yarn 应用状态查询" +Yarn-->>Proc : "最终状态" +Proc-->>Caller : "ProcessResult(退出码/应用ID/PID)" +Caller->>Proc : "cancel()" +Proc->>Proc : "softKill()/hardKill()/destroy()" +``` + +图表来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L81-L128) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L135-L159) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L269-L296) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L171-L192) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L242-L266) + +## 组件详解 + +### BaseCommandProcess 类图 +该类采用抽象基类模式,定义了统一的执行框架与扩展点,子类仅需提供命令解释器、命令文件路径与文件创建逻辑。 + +```mermaid +classDiagram +class BaseCommandProcess { +-Process process +-Consumer~List~logHandler +-JobExecutionRequest jobExecutionRequest +-Logger logger +-String[] logBuffer +-Configurations configurations ++run(executeCommand) ProcessResult +-buildProcess(commandFile) void +#getProcessId(process) int +-printCommand(processBuilder) void ++cancel() void +-softKill(processId) boolean +-hardKill(processId) void +#parseProcessOutput(process) void +-flush(lastFlushTime) long +-clear() void +-close(inReader) void +#commandInterpreter() String +#buildCommandFilePath() String +#createCommandFileIfNotExists(execCommand, commandFile) void +} +class ShellCommandProcess { ++commandInterpreter() String ++buildCommandFilePath() String ++createCommandFileIfNotExists(execCommand, commandFile) void +} +class LivyCommandProcess { ++cancel() void ++post2LivyWithRetry(args) Map ++processResultOfLivyState(sessionId, result) boolean +-post2Livy(args) String +#commandInterpreter() String +#buildCommandFilePath() String +#createCommandFileIfNotExists(execCommand, commandFile) void +} +BaseCommandProcess <|-- ShellCommandProcess +BaseCommandProcess <|-- LivyCommandProcess +``` + +图表来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L41-L364) +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java#L32-L79) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L38-L142) + +章节来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L41-L364) +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java#L32-L79) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L38-L142) + +### ShellCommandProcess 执行流程 +- 命令文件路径:基于执行目录与作业唯一标识生成临时命令文件。 +- 文件内容:写入 shebang、切换工作目录、注入环境变量、追加实际命令。 +- 执行方式:通过 sudo -u 指定租户用户,以 sh 解释器执行命令文件。 +- 日志处理:沿用 BaseCommandProcess 的异步输出解析与缓冲刷新机制。 + +```mermaid +flowchart TD +Start(["开始"]) --> BuildPath["生成命令文件路径"] +BuildPath --> Exists{"命令文件是否存在?"} +Exists -- 是 --> Delete["删除旧文件"] +Exists -- 否 --> Write["写入 shebang/工作目录/环境变量/命令"] +Delete --> Write +Write --> BuildProc["构建 ProcessBuilder 并启动进程"] +BuildProc --> ParseOut["异步解析标准输出并刷新日志"] +ParseOut --> Wait["等待进程结束"] +Wait --> Done(["结束"]) +``` + +图表来源 +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java#L43-L79) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L135-L159) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L269-L296) + +章节来源 +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java#L43-L79) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L135-L159) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L269-L296) + +### LivyCommandProcess 流程与状态机 +- 提交流程:构造参数后提交至 Livy,必要时重试获取 appId。 +- 状态轮询:通过 LivyTaskSubmitHelper 获取会话状态,结合 LivyStates 判断是否成功/失败/未知。 +- 取消流程:优先通过 Livy 删除会话;若失败则回退到 Yarn 杀死应用。 + +```mermaid +sequenceDiagram +participant Caller as "调用方" +participant Ly as "LivyCommandProcess" +participant LTH as "LivyTaskSubmitHelper" +participant LY as "Livy 服务" +participant Yarn as "Yarn" +Caller->>Ly : "run(executeCommand)" +Ly->>LTH : "postToLivy(args)" +LTH->>LY : "POST /batches" +LY-->>LTH : "响应(含 id/appId 或空)" +LTH-->>Ly : "结果" +Ly->>Ly : "retryLivyGetAppId() 重试获取 appId" +loop "轮询状态" +Ly->>LTH : "getResultByLivyId(id)" +LTH->>LY : "GET /batches/{id}" +LY-->>LTH : "状态信息" +LTH-->>Ly : "状态对象" +Ly->>Ly : "LivyStates.toLivyState()" +end +alt "成功" +Ly-->>Caller : "SUCCESS" +else "失败/死亡/未知/Killed" +Ly-->>Caller : "FAILURE" +end +Caller->>Ly : "cancel()" +Ly->>LTH : "deleteByLivy(sessionId, appId)" +alt "Livy 删除失败" +Ly->>LTH : "deleteByYarn(yarnUri, appId)" +end +``` + +图表来源 +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L71-L121) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L113-L165) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L194-L234) +- [LivyStates.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java#L50-L82) + +章节来源 +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L38-L142) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L67-L103) +- [LivyStates.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java#L50-L82) + +### 日志缓冲与刷新机制 +- 缓冲策略:维护一个线程安全的行缓冲列表,达到阈值或时间间隔即刷新。 +- 刷新条件:行数阈值来自 CoreConfig 中的日志配置项;时间间隔同样来自 CoreConfig。 +- 刷新行为:将缓冲中的日志交给上层日志处理器消费,并清空缓冲。 + +```mermaid +flowchart TD +Enter(["进入解析线程"]) --> Read["逐行读取标准输出"] +Read --> Append["加入缓冲列表"] +Append --> Check{"满足刷新条件?"} +Check -- 否 --> Read +Check -- 是 --> Flush["调用日志处理器并清空缓冲"] +Flush --> Read +``` + +图表来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L269-L296) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L298-L311) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java#L32-L39) + +章节来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L269-L311) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java#L32-L39) + +### 取消与终止策略 +- 软终止:尝试通过 kill 发送信号;若进程仍存活,则进行硬终止。 +- 硬终止:发送 kill -9 强制结束。 +- 进程销毁:在必要时调用 destroy 并清理日志缓冲。 + +```mermaid +flowchart TD +Cancel(["cancel()"]) --> GetPid["获取进程PID"] +GetPid --> Soft["尝试 softKill()"] +Soft --> Alive{"进程仍存活?"} +Alive -- 否 --> Destroy["destroy() 并清理日志"] +Alive -- 是 --> Hard["hardKill()"] +Hard --> Destroy +``` + +图表来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L195-L211) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L229-L263) + +章节来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L195-L263) + +### 退出码与应用状态判定 +- 非 Yarn 场景:以进程返回码为依据,0 表示成功,否则失败。 +- Yarn 场景:先以返回码判断,若为 0 再通过 YarnUtils 查询最终状态,依据最终状态确定成功/失败。 + +```mermaid +flowchart TD +Run(["run() 完成"]) --> HasAppId{"存在 Yarn 应用ID?"} +HasAppId -- 否 --> ExitCode{"返回码==0?"} +ExitCode -- 是 --> Success["SUCCESS"] +ExitCode -- 否 --> Failure["FAILURE"] +HasAppId -- 是 --> ExitCode2{"返回码==0?"} +ExitCode2 -- 是 --> YarnState["查询 Yarn 最终状态"] +YarnState --> YarnSuccess{"最终状态成功?"} +YarnSuccess -- 是 --> Success +YarnSuccess -- 否 --> Failure +ExitCode2 -- 否 --> Failure +``` + +图表来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L97-L118) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L171-L192) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L242-L266) + +章节来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L97-L118) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L171-L192) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L242-L266) + +## 依赖关系分析 +- BaseCommandProcess 依赖: + - JobExecutionRequest:获取执行目录、租户、唯一标识等上下文。 + - ProcessUtils:用于打印可读命令行,便于审计。 + - YarnUtils:在 Yarn 场景下查询应用最终状态。 + - CoreConfig:日志缓冲与刷新阈值。 + - ProcessResult:封装退出码、应用ID、进程PID。 +- ShellCommandProcess 依赖: + - 文件系统写入与删除,确保命令文件唯一且可复用。 +- LivyCommandProcess 依赖: + - LivyTaskSubmitHelper:HTTP 交互与重试。 + - LivyStates:状态枚举与转换。 + +```mermaid +graph LR +Base["BaseCommandProcess"] --> JER["JobExecutionRequest"] +Base --> PU["ProcessUtils"] +Base --> YU["YarnUtils"] +Base --> CC["CoreConfig"] +Base --> PR["ProcessResult"] +Sh["ShellCommandProcess"] --> Base +Ly["LivyCommandProcess"] --> Base +Ly --> LTH["LivyTaskSubmitHelper"] +Ly --> LS["LivyStates"] +``` + +图表来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L1-L365) +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java#L1-L80) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L1-L143) +- [ProcessUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ProcessUtils.java#L1-L302) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L1-L270) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java#L1-L41) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L1-L258) +- [LivyStates.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java#L1-L83) + +章节来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L1-L365) +- [ShellCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/ShellCommandProcess.java#L1-L80) +- [LivyCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L1-L143) + +## 性能与稳定性考量 +- 日志缓冲与刷新 + - 通过阈值与时间间隔控制刷新频率,避免频繁 I/O 与内存占用。 + - 建议根据作业输出速率调整 CoreConfig 中的行数阈值与刷新间隔。 +- 进程与线程 + - 输出解析使用单线程守护线程池,避免多线程竞争;注意长时间运行任务的资源占用。 +- 取消策略 + - 软硬终止结合,确保在异常情况下能尽快回收资源。 +- Yarn 场景 + - 依赖 YarnUtils 的最终状态判定,建议在高延迟网络环境下适当增加轮询间隔与重试次数。 +- Livy 场景 + - 提交后重试获取 appId,避免瞬时网络抖动导致的状态缺失;删除失败时回退到 Yarn 杀死应用,提升健壮性。 + +[本节为通用指导,不直接分析具体文件] + +## 故障排查指南 +- 进程无法启动 + - 检查命令文件是否正确生成与写入,确认解释器路径与权限。 + - 查看打印的命令行字符串,定位参数问题。 +- 输出日志缺失 + - 确认输出解析线程是否正常运行,检查日志缓冲阈值是否过大。 + - 核对日志处理器是否被正确传入并触发刷新。 +- 取消无效 + - 检查 PID 是否成功获取,确认 sudo 权限与 kill 命令可用。 + - 若软杀失败,确认硬杀是否执行。 +- Yarn 应用状态异常 + - 核对 YarnUtils 的配置项(如地址、端口、HA 配置)是否正确。 + - 观察最终状态轮询是否被中断或网络异常影响。 +- Livy 提交失败 + - 检查 LivyTaskSubmitHelper 的 URI、认证配置(Kerberos)是否正确。 + - 关注重试逻辑与状态轮询,确认会话 ID 与 appId 获取链路。 + +章节来源 +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L185-L193) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L229-L263) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L171-L192) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L113-L165) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L194-L234) + +## 结论 +BaseCommandProcess 通过统一的进程生命周期管理、日志缓冲与刷新、软硬终止策略以及 Yarn/Livy 的状态判定,为各类命令执行场景提供了稳定可靠的执行框架。ShellCommandProcess 与 LivyCommandProcess 分别覆盖本地/容器与远程批处理场景,二者共享同一抽象基类,确保一致的行为与可观测性。结合合理的日志阈值与取消策略,可在复杂环境中保障作业执行的稳定性与可恢复性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260.md" new file mode 100644 index 00000000..5a7745d2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260.md" @@ -0,0 +1,177 @@ +# 执行器实现 + + +**本文档中引用的文件** +- [AbstractEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractYarnEngineExecutor.java) +- [BaseCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\BaseCommandProcess.java) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) +- [ShellCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\ShellCommandProcess.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) +- [EngineExecutor.java](file://datavines-engine\datavines-engine-api\src\main\java\io\datavines\engine\api\engine\EngineExecutor.java) +- [JobExecutionRequest.java](file://datavines-common\src\main\java\io\datavines\common\entity\JobExecutionRequest.java) +- [ProcessResult.java](file://datavines-common\src\main\java\io\datavines\common\entity\ProcessResult.java) +- [ExecutionStatus.java](file://datavines-common\src\main\java\io\datavines\common\enums\ExecutionStatus.java) +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java) +- [ResourceSchedulePlatformType.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\ResourceSchedulePlatformType.java) + + +## 目录 +1. [引言](#引言) +2. [核心执行器基类分析](#核心执行器基类分析) +3. [资源调度机制对比](#资源调度机制对比) +4. [命令执行封装机制](#命令执行封装机制) +5. [执行器与服务器通信协议](#执行器与服务器通信协议) +6. [性能优化策略](#性能优化策略) +7. [结论](#结论) + +## 引言 +本文档深入分析DataVines大数据平台中执行器模块的实现机制。重点阐述以`AbstractEngineExecutor`为核心的执行器体系结构,详细解析任务调度、资源管理、状态监控等核心功能的实现原理。对比分析基于Livy和Yarn两种不同资源调度平台的执行器实现差异,揭示其在资源管理策略上的不同设计思路。同时,文档将详细说明`BaseCommandProcess`如何封装底层命令执行逻辑,以及执行器与服务器模块之间的通信协议和性能优化策略,为系统维护和二次开发提供全面的技术参考。 + +## 核心执行器基类分析 + +`AbstractEngineExecutor`作为所有执行器的抽象基类,定义了执行器的核心行为和状态管理机制。该类实现了`EngineExecutor`接口,为所有具体执行器提供了统一的框架和基础功能。 + +基类中定义了关键的成员变量,包括`jobExecutionRequest`(作业执行请求)、`logger`(日志记录器)、`cancel`(取消标志)和`processResult`(进程结果)。其中,`cancel`标志采用`volatile`关键字修饰,确保在多线程环境下对取消状态的修改具有可见性,这是实现任务取消功能的基础。 + +基类提供了一个`logHandle`方法,用于统一处理日志输出。该方法将日志列表通过换行符连接后输出,便于日志系统的解析和处理。同时,`isCancel`方法提供了对取消状态的查询功能,允许执行器在运行过程中检查是否已被请求取消。 + +最核心的`buildCommand`方法被声明为抽象方法,强制要求所有子类必须实现具体的命令构建逻辑。这种设计模式体现了模板方法模式的思想,基类定义了算法的骨架(执行流程),而将具体实现延迟到子类中完成,保证了代码的灵活性和可扩展性。 + +**Section sources** +- [AbstractEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractEngineExecutor.java#L27-L56) +- [EngineExecutor.java](file://datavines-engine\datavines-engine-api\src\main\java\io\datavines\engine\api\engine\EngineExecutor.java#L27-L42) +- [JobExecutionRequest.java](file://datavines-common\src\main\java\io\datavines\common\entity\JobExecutionRequest.java#L26-L85) + +## 资源调度机制对比 + +### AbstractLivyEngineExecutor 实现分析 +`AbstractLivyEngineExecutor`是基于Livy服务的执行器基类,它继承自`AbstractEngineExecutor`。该类通过`LivyCommandProcess`与Livy REST API进行交互,实现对Spark作业的远程提交和管理。 + +其核心特点是将作业的生命周期管理委托给Livy服务。在`cancel`方法中,执行器首先调用`livyCommandProcess.cancel()`,该方法最终会通过`LivyTaskSubmitHelper`向Livy服务器发送DELETE请求,优雅地终止指定的会话。这种方式避免了直接操作底层YARN应用的复杂性,提供了更高层次的抽象。 + +```mermaid +sequenceDiagram +participant 执行器 as AbstractLivyEngineExecutor +participant 命令进程 as LivyCommandProcess +participant 提交助手 as LivyTaskSubmitHelper +participant Livy服务器 as Livy REST API +执行器->>命令进程 : cancel() +命令进程->>提交助手 : deleteByLivy(sessionId, appId) +提交助手->>Livy服务器 : DELETE /sessions/{sessionId} +Livy服务器-->>提交助手 : 200 OK +提交助手-->>命令进程 : 删除成功 +命令进程-->>执行器 : 取消完成 +``` + +**Diagram sources** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java#L23-L36) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L38-L142) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) + +### AbstractYarnEngineExecutor 实现分析 +`AbstractYarnEngineExecutor`是基于YARN资源管理器的执行器基类。与Livy方式不同,它通过`ShellCommandProcess`直接在本地执行shell命令来提交和管理YARN应用。 + +其`cancel`方法的实现更为直接和底层。在设置取消标志后,它首先调用`shellCommandProcess.cancel()`来终止本地进程,然后通过`killYarnApplication`方法构建并执行`yarn application -kill`命令,直接向YARN ResourceManager发送请求以终止指定的应用程序。这种方法绕过了Livy层,对YARN有更直接的控制权。 + +```mermaid +sequenceDiagram +participant 执行器 as AbstractYarnEngineExecutor +participant 命令进程 as ShellCommandProcess +participant YARN as YARN ResourceManager +执行器->>命令进程 : cancel() +命令进程->>执行器 : softKill(pid) +执行器->>YARN : sudo kill {pid} +YARN-->>执行器 : 终止进程 +执行器->>YARN : sudo -u user yarn application -kill {appId} +YARN-->>执行器 : 应用已终止 +``` + +**Diagram sources** +- [AbstractYarnEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractYarnEngineExecutor.java#L25-L59) +- [ShellCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\ShellCommandProcess.java#L32-L79) + +### 调度平台类型枚举 +`ResourceSchedulePlatformType`枚举类定义了系统支持的三种资源调度平台:`LOCAL`、`YARN`和`K8S`。该枚举为执行器的选择和配置提供了类型安全的定义,确保了系统在不同环境下的可移植性和配置一致性。 + +**Section sources** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java#L23-L36) +- [AbstractYarnEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractYarnEngineExecutor.java#L25-L59) +- [ResourceSchedulePlatformType.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\ResourceSchedulePlatformType.java#L19-L60) + +## 命令执行封装机制 + +`BaseCommandProcess`是所有命令执行进程的抽象基类,它封装了底层命令执行的通用逻辑,包括进程创建、输出解析、日志处理和进程终止等。 + +### 核心执行流程 +`run`方法是命令执行的核心入口。它首先检查执行命令的有效性,然后通过`buildCommandFilePath`和`createCommandFileIfNotExists`构建并写入命令脚本文件。接着,使用`ProcessBuilder`配置并启动进程,其中巧妙地使用`sudo -u`命令以指定租户用户身份执行,实现了多租户环境下的安全隔离。 + +### 进程输出与日志处理 +`parseProcessOutput`方法启动一个守护线程,持续读取进程的标准输出流,并将日志行缓存到`logBuffer`中。`flush`方法根据配置的行数阈值(`LOG_CACHE_ROW_NUM`)或时间间隔(`LOG_FLUSH_INTERVAL`)将日志批量刷新到日志处理器,实现了高效的日志流处理,避免了频繁的I/O操作。 + +### 进程终止机制 +`cancel`方法提供了优雅的进程终止机制。它首先尝试`softKill`(发送SIGTERM信号),如果进程仍在运行,则进行`hardKill`(发送SIGKILL信号)。这种分层的终止策略既保证了进程能够有机会清理资源,又确保了在必要时能够强制终止。 + +```mermaid +flowchart TD +Start([开始执行]) --> BuildCommand["构建命令文件"] +BuildCommand --> StartProcess["启动进程"] +StartProcess --> WaitForExit["等待进程退出"] +WaitForExit --> CheckExitCode["检查退出码"] +CheckExitCode --> |退出码为0| CheckYarnState["检查YARN状态"] +CheckExitCode --> |退出码非0| SetFailure["设置失败状态"] +CheckYarnState --> |YARN状态成功| SetSuccess["设置成功状态"] +CheckYarnState --> |YARN状态失败| SetFailure +SetSuccess --> End([执行完成]) +SetFailure --> End +``` + +**Diagram sources** +- [BaseCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\BaseCommandProcess.java#L41-L364) +- [ShellCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\ShellCommandProcess.java#L32-L79) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L38-L142) + +**Section sources** +- [BaseCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\BaseCommandProcess.java#L41-L364) +- [ShellCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\ShellCommandProcess.java#L32-L79) + +## 执行器与服务器通信协议 + +执行器与服务器之间的通信主要通过`LivyTaskSubmitHelper`类实现,该类封装了与Livy REST API交互的所有细节。 + +### HTTP通信机制 +`LivyTaskSubmitHelper`使用`RestTemplate`和`KerberosRestTemplate`作为HTTP客户端。它根据配置决定是否启用Kerberos认证。当`livy.need.kerberos`配置为`true`时,使用`KerberosRestTemplate`进行安全通信;否则,使用普通的`RestTemplate`。 + +### 状态监控与重试机制 +`processResultOfLivyState`方法实现了对Livy会话状态的轮询监控。它在一个循环中持续调用`getResultByLivyId`获取会话状态,直到作业成功、失败或被取消。`retryLivyGetAppId`方法在初次提交后,如果返回结果中没有立即包含`appId`,会进行指定次数的重试,以应对Livy服务的延迟响应。 + +### 状态映射 +`LivyStates`枚举类定义了Livy服务的所有可能状态,并提供了`toLivyState`静态方法将JSON响应中的状态字符串转换为对应的枚举值。`isActive`和`isHealthy`方法提供了对状态的高级判断,用于指导执行器的后续行为。 + +**Section sources** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L38-L142) +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java#L24-L82) + +## 性能优化策略 + +### 日志缓冲与批量刷新 +`BaseCommandProcess`通过`logBuffer`和`flush`机制实现了日志的批量处理。这避免了为每一行日志都进行一次I/O操作,显著降低了系统调用的开销。配置项`LOG_CACHE_ROW_NUM`和`LOG_FLUSH_INTERVAL`允许根据实际负载调整缓冲策略,在内存使用和日志实时性之间取得平衡。 + +### 守护线程与资源清理 +`parseProcessOutput`方法使用`ThreadUtils.newDaemonSingleThreadExecutor`创建守护线程来处理输出流。守护线程不会阻止JVM退出,确保了在主进程结束时相关资源能够被正确回收。`clear`和`close`方法确保了在异常情况下也能及时清理缓冲区和关闭流。 + +### 进程ID反射获取 +`getProcessId`方法通过反射访问`Process`对象的私有`pid`字段来获取进程ID。这是一种绕过Java标准API限制的技巧,为执行器提供了对底层进程的直接控制能力,是实现`softKill`和`hardKill`功能的基础。 + +### 配置驱动的灵活性 +整个执行器框架高度依赖`Configurations`对象进行配置管理。从日志缓冲大小到Livy重试次数,几乎所有行为都可以通过配置文件进行调整,无需修改代码,极大地提高了系统的灵活性和可维护性。 + +**Section sources** +- [BaseCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\BaseCommandProcess.java#L41-L364) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) +- [CoreConfig.java](file://datavines-common\src\main\java\io\datavines\common\config\CoreConfig.java) + +## 结论 +DataVines的执行器实现展现了一个设计精良、层次分明的分布式任务执行框架。通过`AbstractEngineExecutor`基类定义了统一的执行契约,而`AbstractLivyEngineExecutor`和`AbstractYarnEngineExecutor`则分别针对不同的资源调度平台提供了具体的实现。`BaseCommandProcess`对底层命令执行进行了优雅的封装,处理了进程管理、日志流和资源清理等复杂细节。`LivyTaskSubmitHelper`则实现了与外部服务的可靠通信。整个系统通过配置驱动和合理的性能优化策略,确保了在大规模数据处理场景下的稳定性和高效性。该设计为系统的扩展和维护提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/\346\212\275\350\261\241\346\211\247\350\241\214\345\231\250\345\237\272\347\261\273.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/\346\212\275\350\261\241\346\211\247\350\241\214\345\231\250\345\237\272\347\261\273.md" new file mode 100644 index 00000000..8f566009 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\231\250\345\256\236\347\216\260/\346\212\275\350\261\241\346\211\247\350\241\214\345\231\250\345\237\272\347\261\273.md" @@ -0,0 +1,254 @@ +# 抽象执行器基类 + + +**本文档引用的文件** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +`AbstractEngineExecutor` 是 DataVines 框架中所有执行器的抽象基类,定义了执行器的核心行为和生命周期管理机制。该基类通过实现 `EngineExecutor` 接口,为各种执行引擎(如 Spark、Flink、Livy 等)提供了统一的接口规范。其主要职责包括任务调度、资源管理、状态监控、日志处理和错误处理。通过继承此基类,开发者可以快速实现自定义执行器,同时确保与上层引擎和底层执行环境的兼容性。 + +## 项目结构 +DataVines 的执行器模块采用插件化架构设计,核心执行器基类位于 `datavines-engine-executor` 模块中,具体实现类分布在各个引擎插件模块中。这种设计实现了核心逻辑与具体实现的分离,提高了代码的可维护性和扩展性。 + +```mermaid +graph TD +subgraph "核心模块" +AbstractEngineExecutor["抽象执行器基类
AbstractEngineExecutor"] +EngineExecutor["执行器接口
EngineExecutor"] +end +subgraph "具体实现模块" +SparkEngineExecutor["Spark执行器
SparkEngineExecutor"] +FlinkEngineExecutor["Flink执行器
FlinkEngineExecutor"] +LocalEngineExecutor["本地执行器
LocalEngineExecutor"] +LivyEngineExecutor["Livy执行器
LivyEngineExecutor"] +end +EngineExecutor --> AbstractEngineExecutor +AbstractEngineExecutor --> SparkEngineExecutor +AbstractEngineExecutor --> FlinkEngineExecutor +AbstractEngineExecutor --> LocalEngineExecutor +AbstractEngineExecutor --> LivyEngineExecutor +style AbstractEngineExecutor fill:#f9f,stroke:#333 +style EngineExecutor fill:#bbf,stroke:#333,color:#fff +``` + +**图示来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) + +## 核心组件 +`AbstractEngineExecutor` 作为所有执行器的基类,封装了执行器的通用功能和生命周期管理方法。其核心组件包括任务请求、日志记录器、取消标志和处理结果等字段,以及初始化、执行、后处理、取消和状态检查等方法。该类通过抽象方法 `buildCommand` 强制子类实现具体的命令构建逻辑,确保了执行器的灵活性和可扩展性。 + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) + +## 架构概述 +`AbstractEngineExecutor` 的架构设计遵循了面向对象的继承和多态原则,通过抽象基类定义通用行为,具体实现类负责特定引擎的细节处理。该架构支持多种执行模式,包括本地执行、YARN 集群执行和 Livy 会话执行,通过继承不同的抽象子类(如 `AbstractYarnEngineExecutor` 和 `AbstractLivyEngineExecutor`)来实现。 + +```mermaid +classDiagram +class EngineExecutor { +<> ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++after() ++cancel() ++isCancel() ++getProcessResult() ++getTaskRequest() +} +class AbstractEngineExecutor { +-JobExecutionRequest jobExecutionRequest +-Logger logger +-volatile boolean cancel +-ProcessResult processResult ++logHandle(String[]) ++isCancel() +#buildCommand() +} +class AbstractYarnEngineExecutor { +-ShellCommandProcess shellCommandProcess ++cancel() +-killYarnApplication() +} +class AbstractLivyEngineExecutor { +-LivyCommandProcess livyCommandProcess ++cancel() +} +class LocalEngineExecutor { +-LocalDataVinesBootstrap bootstrap ++init() ++execute() ++after() ++cancel() ++getProcessResult() ++getTaskRequest() ++buildCommand() +} +EngineExecutor <|.. AbstractEngineExecutor +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +AbstractEngineExecutor <|-- AbstractLivyEngineExecutor +AbstractEngineExecutor <|-- LocalEngineExecutor +AbstractYarnEngineExecutor <|-- SparkEngineExecutor +AbstractYarnEngineExecutor <|-- FlinkEngineExecutor +``` + +**图示来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) + +## 详细组件分析 + +### 生命周期管理方法分析 +`AbstractEngineExecutor` 定义了一套完整的生命周期管理方法,确保执行器能够正确地初始化、执行任务、处理后续操作和响应取消请求。 + +#### 初始化方法 (init) +`init` 方法负责初始化执行器所需的资源,包括设置任务请求、日志记录器和配置信息。该方法在执行器创建后立即调用,为后续的执行操作做好准备。 + +#### 执行方法 (execute) +`execute` 方法是执行器的核心,负责执行具体的任务逻辑。子类需要根据具体的执行环境和需求实现该方法。 + +#### 后处理方法 (after) +`after` 方法在任务执行完成后调用,用于清理资源和执行收尾工作。 + +#### 取消方法 (cancel) +`cancel` 方法用于取消正在执行的任务。不同的执行器实现可能会有不同的取消策略,例如通过终止进程或发送取消信号。 + +#### 状态检查方法 (isCancel) +`isCancel` 方法用于检查任务是否已被取消,返回一个布尔值表示当前的取消状态。 + +```mermaid +sequenceDiagram +participant JobRunner +participant EngineExecutor +participant AbstractEngineExecutor +JobRunner->>EngineExecutor : init() +JobRunner->>EngineExecutor : execute() +alt 任务正常执行 +EngineExecutor->>EngineExecutor : 执行任务逻辑 +EngineExecutor-->>JobRunner : 返回成功状态 +else 任务被取消 +JobRunner->>EngineExecutor : cancel() +EngineExecutor->>AbstractEngineExecutor : 设置cancel标志 +EngineExecutor-->>JobRunner : 返回取消状态 +end +JobRunner->>EngineExecutor : after() +``` + +**图示来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) + +### 配置参数处理 +执行器通过 `JobExecutionRequest` 对象接收配置参数,该对象包含了任务执行所需的所有信息,如应用参数、租户代码、任务唯一标识等。执行器在初始化阶段解析这些参数,并根据需要进行相应的配置。 + +### 日志管理 +`AbstractEngineExecutor` 提供了 `logHandle` 方法用于统一处理日志输出。该方法将日志列表格式化后输出到日志记录器,便于日志的解析和监控。 + +```mermaid +flowchart TD +Start([开始]) --> FormatLogs["格式化日志列表"] +FormatLogs --> OutputLogs["输出日志到记录器"] +OutputLogs --> End([结束]) +``` + +**图示来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) + +### 错误处理策略 +执行器通过 `ProcessResult` 对象返回执行结果,包括退出状态码、进程ID和应用ID等信息。上层调用者可以根据这些信息判断任务的执行状态,并采取相应的错误处理措施。 + +```mermaid +flowchart TD +Execute["执行任务"] --> CheckResult["检查执行结果"] +CheckResult --> |成功| Success["记录成功状态"] +CheckResult --> |失败| Failure["记录失败状态"] +CheckResult --> |已取消| Cancelled["记录取消状态"] +Success --> End +Failure --> End +Cancelled --> End +``` + +**图示来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) + +## 依赖分析 +`AbstractEngineExecutor` 依赖于多个核心模块,包括 `datavines-common` 中的实体类和配置类,`datavines-engine-api` 中的接口定义,以及具体的执行器实现类。这些依赖关系确保了执行器能够与框架的其他部分无缝集成。 + +```mermaid +graph TD +AbstractEngineExecutor --> JobExecutionRequest +AbstractEngineExecutor --> ProcessResult +AbstractEngineExecutor --> Configurations +AbstractEngineExecutor --> Logger +AbstractEngineExecutor --> EngineExecutor +JobExecutionRequest --> CommonConstants +ProcessResult --> CommonConstants +Configurations --> CoreConfig +Logger --> SLF4J +style AbstractEngineExecutor fill:#f9f,stroke:#333 +``` + +**图示来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) +- [ProcessResult.java](file://datavines-common/src/main/java/io/datavines/common/entity/ProcessResult.java) +- [Configurations.java](file://datavines-common/src/main/java/io/datavines/common/config/Configurations.java) + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) + +## 性能考虑 +在设计和实现执行器时,需要考虑以下几个性能方面: +- **资源管理**:合理分配和释放执行过程中使用的资源,避免内存泄漏和资源浪费。 +- **并发处理**:支持多任务并发执行,提高系统的吞吐量。 +- **日志输出**:优化日志输出频率和格式,减少I/O开销。 +- **错误恢复**:实现健壮的错误处理机制,确保系统在异常情况下能够快速恢复。 + +## 故障排除指南 +在使用 `AbstractEngineExecutor` 时,可能会遇到以下常见问题: +- **任务无法启动**:检查 `JobExecutionRequest` 中的参数是否正确,确保所有必需的配置都已提供。 +- **任务执行超时**:调整任务的超时设置,或优化任务逻辑以减少执行时间。 +- **资源不足**:检查集群资源使用情况,必要时增加资源配额。 +- **日志无法输出**:确认日志配置是否正确,检查日志文件路径和权限。 + +**本节来源** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) + +## 结论 +`AbstractEngineExecutor` 作为 DataVines 框架中所有执行器的基类,提供了统一的接口和通用的功能实现,极大地简化了新执行器的开发工作。通过继承该基类,开发者可以专注于具体执行逻辑的实现,而不必关心底层的资源管理和生命周期控制。这种设计不仅提高了代码的复用性和可维护性,还确保了不同执行器之间的一致性和兼容性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/Flink\346\211\247\350\241\214\345\274\225\346\223\216.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/Flink\346\211\247\350\241\214\345\274\225\346\223\216.md" new file mode 100644 index 00000000..3a7c31a9 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/Flink\346\211\247\350\241\214\345\274\225\346\223\216.md" @@ -0,0 +1,355 @@ +# Flink执行引擎 + + +**本文档引用的文件** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java) +- [FlinkDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-core/src/main/java/io/datavines/engine/flink/core/FlinkDataVinesBootstrap.java) +- [FlinkStreamExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/stream/FlinkStreamExecution.java) +- [FlinkConfiguration.tsx](file://datavines-ui/src/view/Main/Config/FlinkConfiguration.tsx) +- [FlinkConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-flink/src/main/java/io/datavines/connector/plugin/FlinkConnectorFactory.java) + + +## 目录 +1. [Flink执行引擎概述](#flink执行引擎概述) +2. [FlinkEngineExecutor实现原理](#flinkengineexecutor实现原理) +3. [任务提交流程分析](#任务提交流程分析) +4. [Flink配置构建器](#flink配置构建器) +5. [Flink运行时环境初始化](#flink运行时环境初始化) +6. [资源管理策略](#资源管理策略) +7. [性能调优参数与最佳实践](#性能调优参数与最佳实践) +8. [Flink Connector与DataVines集成](#flink-connector与datavines集成) + +## Flink执行引擎概述 + +Flink执行引擎是DataVines数据质量平台的核心组件之一,负责执行基于Apache Flink的流式和批处理作业。该引擎通过抽象化的执行器接口,实现了对Flink作业的统一管理和调度。Flink执行引擎支持多种部署模式,包括本地模式、YARN会话模式、YARN单作业模式和YARN应用模式,能够灵活适应不同的生产环境需求。 + +Flink执行引擎的设计遵循了模块化和可扩展的原则,通过SPI(Service Provider Interface)机制实现了组件的动态加载。这种设计使得引擎能够轻松集成新的数据源、转换器和接收器,为数据质量检查提供了强大的扩展能力。引擎的核心功能包括作业配置构建、运行时环境初始化、任务提交与监控、资源管理以及结果收集等。 + +**Section sources** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L1-L183) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java#L1-L94) + +## FlinkEngineExecutor实现原理 + +FlinkEngineExecutor是Flink执行引擎的核心实现类,继承自AbstractYarnEngineExecutor,负责Flink作业的执行和管理。该类实现了EngineExecutor接口,提供了初始化、执行、取消和结果获取等关键方法。 + +FlinkEngineExecutor的主要职责包括: +1. 初始化执行环境,设置线程名称和日志记录器 +2. 构建Flink命令行参数 +3. 执行Flink作业并监控执行过程 +4. 处理日志输出和执行结果 +5. 支持作业取消和YARN应用终止 + +在初始化过程中,FlinkEngineExecutor会根据作业执行请求设置线程名称,便于日志追踪和监控。执行过程中,通过ShellCommandProcess执行构建的Flink命令,并实时处理输出日志。当需要取消作业时,除了调用ShellCommandProcess的取消方法外,还会通过YarnUtils获取YARN应用ID并执行kill命令,确保作业被彻底终止。 + +```mermaid +classDiagram +class FlinkEngineExecutor { +-Configurations configurations +-JobExecutionRequest jobExecutionRequest +-Logger logger +-ProcessResult processResult +-BaseCommandProcess shellCommandProcess +-boolean cancel ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++buildCommand() String ++getProcessResult() ProcessResult ++cancel() void ++logHandle(String[]) void ++isCancel() boolean +} +class AbstractYarnEngineExecutor { ++killYarnApplication() void +} +FlinkEngineExecutor --|> AbstractYarnEngineExecutor : 继承 +FlinkEngineExecutor --> Configurations : 使用 +FlinkEngineExecutor --> JobExecutionRequest : 使用 +FlinkEngineExecutor --> Logger : 使用 +FlinkEngineExecutor --> ProcessResult : 使用 +FlinkEngineExecutor --> BaseCommandProcess : 使用 +``` + +**Diagram sources** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L38-L182) + +**Section sources** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L38-L182) + +## 任务提交流程分析 + +Flink任务提交流程是Flink执行引擎的核心工作流程,从作业配置到最终执行的完整过程。该流程始于FlinkEngineExecutor的execute方法,通过构建Flink命令行并执行来启动作业。 + +任务提交的主要步骤包括: +1. 解析作业执行请求中的引擎参数,转换为FlinkParameters对象 +2. 设置主JAR文件路径,从配置中获取Flink作业JAR名称 +3. 将作业配置序列化为JSON字符串,并进行Base64编码作为主参数 +4. 设置主类为FlinkDataVinesBootstrap +5. 构建完整的Flink命令行参数 +6. 执行命令并监控执行过程 + +在构建命令行参数时,FlinkArgsUtils工具类发挥了关键作用。该工具类根据FlinkParameters中的配置,生成符合Flink CLI规范的参数列表。参数构建过程考虑了部署模式、并行度、内存配置、队列设置等多种因素,确保作业能够正确提交到目标环境。 + +```mermaid +sequenceDiagram +participant FlinkEngineExecutor +participant FlinkArgsUtils +participant ShellCommandProcess +participant FlinkCLI +FlinkEngineExecutor->>FlinkEngineExecutor : execute() +FlinkEngineExecutor->>FlinkEngineExecutor : buildCommand() +FlinkEngineExecutor->>FlinkEngineExecutor : 解析FlinkParameters +FlinkEngineExecutor->>FlinkEngineExecutor : 设置主JAR路径 +FlinkEngineExecutor->>FlinkEngineExecutor : 序列化作业配置 +FlinkEngineExecutor->>FlinkArgsUtils : buildArgs(FlinkParameters) +FlinkArgsUtils-->>FlinkEngineExecutor : 返回参数列表 +FlinkEngineExecutor->>FlinkEngineExecutor : 构建完整命令 +FlinkEngineExecutor->>ShellCommandProcess : run(command) +ShellCommandProcess->>FlinkCLI : 执行Flink命令 +FlinkCLI-->>ShellCommandProcess : 返回执行结果 +ShellCommandProcess-->>FlinkEngineExecutor : 返回ProcessResult +``` + +**Diagram sources** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L72-L126) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L35-L124) + +**Section sources** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L72-L126) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L35-L124) + +## Flink配置构建器 + +Flink配置构建器负责生成Flink作业的配置参数,这些参数通过FlinkParameters类进行封装。配置构建器的主要功能是将用户界面或API提供的配置信息转换为Flink CLI可识别的参数格式。 + +FlinkParameters类包含以下关键配置项: +- **mainJar**: 主JAR文件路径 +- **mainClass**: 主类名称 +- **deployMode**: 部署模式(local, yarn-session, yarn-per-job, yarn-application) +- **taskManagerCount**: TaskManager数量 +- **taskManagerMemory**: TaskManager内存大小 +- **jobManagerMemory**: JobManager内存大小 +- **mainArgs**: 主方法参数 +- **yarnQueue**: YARN队列名称 +- **jobName**: 作业名称 +- **parallelism**: 并行度 +- **flinkOthers**: 其他Flink参数 +- **jars**: 附加JAR文件 +- **tags**: 作业标签 + +这些配置项通过FlinkArgsUtils工具类转换为Flink命令行参数。例如,部署模式决定了使用"run"还是"run-application"命令,内存配置转换为-Djobmanager.memory.process.size和-Dtaskmanager.memory.process.size系统属性,YARN队列配置转换为-Dyarn.application.queue属性等。 + +```mermaid +classDiagram +class FlinkParameters { ++String mainJar ++String mainClass ++String deployMode ++String taskManagerCount ++String taskManagerMemory ++String jobManagerMemory ++String mainArgs ++String yarnQueue ++String jobName ++int parallelism ++String flinkOthers ++String jars ++String tags +} +class FlinkArgsUtils { ++String[] buildArgs(FlinkParameters) +} +FlinkArgsUtils --> FlinkParameters : 使用 +``` + +**Diagram sources** +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L24-L124) + +**Section sources** +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L24-L124) + +## Flink运行时环境初始化 + +Flink运行时环境由FlinkRuntimeEnvironment类负责初始化和管理。该类实现了RuntimeEnvironment接口,为Flink作业提供了执行所需的环境配置。 + +运行时环境初始化的主要步骤包括: +1. 创建StreamExecutionEnvironment实例 +2. 根据配置设置执行模式(流模式或批模式) +3. 创建StreamTableEnvironment实例 +4. 准备执行环境 + +在prepare方法中,首先通过StreamExecutionEnvironment.getExecutionEnvironment()获取执行环境实例。然后根据配置中的TYPE参数判断是流模式还是批模式,如果是批模式则设置RuntimeExecutionMode.BATCH。最后创建StreamTableEnvironment实例,为后续的Table API和SQL操作提供支持。 + +FlinkRuntimeEnvironment还提供了配置检查、执行实例获取和环境停止等方法。其中getExecution方法返回FlinkStreamExecution实例,该实例负责具体的作业执行逻辑,包括数据源注册、转换处理和结果输出等。 + +```mermaid +classDiagram +class FlinkRuntimeEnvironment { +-StreamExecutionEnvironment env +-StreamTableEnvironment tableEnv +-Config config ++setConfig(Config) void ++getConfig() Config ++checkConfig() CheckResult ++getExecution() Execution ++prepare() void ++stop() void +} +class FlinkStreamExecution { +-FlinkRuntimeEnvironment flinkEnv +-Config config ++setConfig(Config) void ++getConfig() Config ++checkConfig() CheckResult ++prepare() void ++execute(FlinkStreamSource[], FlinkStreamTransform[], FlinkStreamSink[]) void ++stop() void +} +FlinkRuntimeEnvironment --> StreamExecutionEnvironment : 包含 +FlinkRuntimeEnvironment --> StreamTableEnvironment : 包含 +FlinkRuntimeEnvironment --> Config : 包含 +FlinkRuntimeEnvironment --> FlinkStreamExecution : 创建 +``` + +**Diagram sources** +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java#L33-L93) +- [FlinkStreamExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/stream/FlinkStreamExecution.java#L38-L125) + +**Section sources** +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java#L33-L93) +- [FlinkStreamExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/stream/FlinkStreamExecution.java#L38-L125) + +## 资源管理策略 + +Flink执行引擎的资源管理策略主要体现在内存配置、并行度控制和YARN资源调度三个方面。这些策略通过FlinkParameters中的配置项实现,确保作业能够高效利用集群资源。 + +内存配置方面,引擎支持独立设置JobManager和TaskManager的内存大小。JobManager内存通过jobManagerMemory参数配置,对应Flink的jobmanager.memory.process.size属性;TaskManager内存通过taskManagerMemory参数配置,对应taskmanager.memory.process.size属性。这种细粒度的内存控制有助于优化作业性能,避免资源浪费。 + +并行度控制通过parallelism参数实现,允许用户根据数据量和处理需求设置合适的并行度。较高的并行度可以提高处理速度,但也会增加资源消耗;较低的并行度节省资源,但可能影响处理效率。最佳实践是根据集群资源和数据特征进行调优。 + +YARN资源调度方面,引擎支持指定YARN队列和应用标签。yarnQueue参数用于指定作业提交到的YARN队列,便于资源隔离和优先级管理;tags参数用于标记作业,便于监控和管理。此外,部署模式的选择也影响资源管理策略,YARN会话模式适合多作业共享资源,YARN单作业模式适合独占资源的长时间作业。 + +```mermaid +flowchart TD +A[资源管理策略] --> B[内存配置] +A --> C[并行度控制] +A --> D[YARN资源调度] +B --> B1[JobManager内存] +B --> B2[TaskManager内存] +C --> C1[并行度设置] +C --> C2[资源利用率优化] +D --> D1[YARN队列] +D --> D2[应用标签] +D --> D3[部署模式] +D3 --> D31[本地模式] +D3 --> D32[YARN会话模式] +D3 --> D33[YARN单作业模式] +D3 --> D34[YARN应用模式] +``` + +**Diagram sources** +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L73-L96) + +**Section sources** +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) +- [FlinkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkArgsUtils.java#L73-L96) + +## 性能调优参数与最佳实践 + +Flink执行引擎提供了丰富的性能调优参数,帮助用户优化作业性能。这些参数主要通过FlinkParameters类配置,并在作业提交时转换为Flink CLI参数。 + +关键性能调优参数包括: +- **并行度(parallelism)**: 控制作业的并行处理能力,建议根据集群CPU核心数和数据量设置 +- **内存配置**: 合理设置JobManager和TaskManager内存,避免OOM错误 +- **部署模式**: 根据作业特征选择合适的部署模式 +- **YARN队列**: 将作业提交到合适的YARN队列,确保资源可用性 +- **其他Flink参数(flinkOthers)**: 支持传递任意Flink配置参数 + +最佳实践建议: +1. **内存调优**: 根据作业复杂度和数据量合理设置内存,建议初始设置为2-4GB,根据实际运行情况调整 +2. **并行度设置**: 一般设置为集群CPU核心数的80%-90%,避免过度并行导致调度开销 +3. **部署模式选择**: 短期作业使用YARN单作业模式,长期运行作业使用YARN会话模式 +4. **资源隔离**: 使用YARN队列实现不同业务线的资源隔离 +5. **监控与调优**: 定期监控作业性能指标,根据瓶颈进行针对性调优 + +前端界面通过FlinkConfiguration组件提供了这些参数的配置界面,用户可以直观地设置各种参数。配置信息通过API传递到后端,由FlinkEngineExecutor处理并提交作业。 + +```mermaid +classDiagram +class FlinkConfiguration { ++deployMode : String ++flinkHome : String ++jobmanagerMemory : String ++taskmanagerMemory : String ++parallelism : int ++yarnQueue : String ++jobName : String ++flinkOthers : String +} +class FlinkParameters { ++deployMode : String ++jobManagerMemory : String ++taskManagerMemory : String ++parallelism : int ++yarnQueue : String ++jobName : String ++flinkOthers : String +} +FlinkConfiguration --> FlinkParameters : 映射 +``` + +**Diagram sources** +- [FlinkConfiguration.tsx](file://datavines-ui/src/view/Main/Config/FlinkConfiguration.tsx#L13-L84) +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) + +**Section sources** +- [FlinkConfiguration.tsx](file://datavines-ui/src/view/Main/Config/FlinkConfiguration.tsx#L13-L84) +- [FlinkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/parameter/FlinkParameters.java#L22-L49) + +## Flink Connector与DataVines集成 + +Flink Connector与DataVines的集成通过FlinkConnectorFactory类实现。该类继承自AbstractJdbcConnectorFactory,为Flink引擎提供了JDBC连接器的功能。 + +集成的主要组件包括: +- **FlinkDialect**: 实现Flink SQL方言,处理Flink特有的SQL语法和数据类型 +- **FlinkMetricScript**: 生成Flink环境下的度量脚本,用于数据质量检查 +- **FlinkConnectorFactory**: 连接器工厂,负责创建Flink相关的组件实例 + +FlinkConnectorFactory的showInFrontend方法返回false,表明该连接器不直接在前端界面显示,而是作为内部组件使用。这种设计使得Flink引擎能够无缝集成到DataVines平台中,而不需要用户直接配置Flink连接器。 + +数据传输机制基于Flink的DataStream API和Table API。数据源通过FlinkStreamSource接口实现,将外部数据源的数据转换为DataStream;转换逻辑通过FlinkStreamTransform接口实现,对数据流进行处理;结果输出通过FlinkStreamSink接口实现,将处理结果写入目标系统。这种基于流的处理模型确保了数据质量检查的实时性和高效性。 + +```mermaid +classDiagram +class FlinkConnectorFactory { ++getDialect() Dialect ++getMetricScript() MetricScript ++showInFrontend() Boolean +} +class FlinkDialect { ++quoteIdentifier(String) String ++getLimitClause(int) String ++getOffsetLimitClause(int, int) String +} +class FlinkMetricScript { ++getMetricQuery(String, String) String ++getRowCountQuery(String) String +} +FlinkConnectorFactory --> FlinkDialect : 创建 +FlinkConnectorFactory --> FlinkMetricScript : 创建 +FlinkConnectorFactory --|> AbstractJdbcConnectorFactory : 继承 +``` + +**Diagram sources** +- [FlinkConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-flink/src/main/java/io/datavines/connector/plugin/FlinkConnectorFactory.java#L21-L52) +- [FlinkDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-flink/src/main/java/io/datavines/connector/plugin/FlinkDialect.java) +- [FlinkMetricScript.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-flink/src/main/java/io/datavines/connector/plugin/FlinkMetricScript.java) + +**Section sources** +- [FlinkConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-flink/src/main/java/io/datavines/connector/plugin/FlinkConnectorFactory.java#L21-L52) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/Livy\346\211\247\350\241\214\345\274\225\346\223\216.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/Livy\346\211\247\350\241\214\345\274\225\346\223\216.md" new file mode 100644 index 00000000..931f9563 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/Livy\346\211\247\350\241\214\345\274\225\346\223\216.md" @@ -0,0 +1,258 @@ +# Livy执行引擎 + + +**本文档引用的文件** +- [LivyEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [LivyCommandProcess.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) +- [LivyStates.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java) +- [LivySparkParameters.java](file://datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/parameter/LivySparkParameters.java) +- [SparkParameters.java](file://datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/parameter/SparkParameters.java) +- [SparkConstants.java](file://datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/parameter/SparkConstants.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [Livy作业提交机制](#livy作业提交机制) +4. [Livy连接配置与会话管理](#livy连接配置与会话管理) +5. [任务状态监控与结果获取](#任务状态监控与结果获取) +6. [故障排查指南](#故障排查指南) +7. [性能优化建议](#性能优化建议) +8. [高可用与安全认证](#高可用与安全认证) + +## 简介 +Livy执行引擎是DataVines平台中用于通过Livy REST API提交和管理Spark作业的核心组件。该引擎通过抽象化的执行器模式,实现了与Spark引擎的代码复用,同时针对Livy特有的会话管理和状态监控机制进行了专门的实现。Livy执行引擎的主要功能包括:作业提交、会话管理、状态监控、结果获取和作业取消等。它通过REST API与Livy服务器通信,实现了对Spark作业的远程提交和管理,为数据质量检测等大数据处理任务提供了可靠的执行环境。 + +## 核心组件 + +Livy执行引擎由多个核心组件构成,这些组件协同工作以实现完整的作业执行流程。主要组件包括LivyEngineExecutor、LivyCommandProcess、LivyTaskSubmitHelper和LivyStates等。LivyEngineExecutor作为执行引擎的主类,负责初始化、执行和管理Spark作业的整个生命周期。LivyCommandProcess处理与Livy服务器的通信细节,包括作业提交和状态查询。LivyTaskSubmitHelper封装了与Livy REST API交互的具体实现,提供了POST、GET和DELETE等HTTP操作。LivyStates则定义了Livy会话的各种状态,用于作业状态的监控和判断。 + +**本文档引用的文件** +- [LivyEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [LivyCommandProcess.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) +- [LivyStates.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java) + +## Livy作业提交机制 + +Livy执行引擎通过Livy REST API提交Spark作业的实现机制主要由LivyEngineExecutor和LivyCommandProcess两个核心类协同完成。作业提交流程始于LivyEngineExecutor的execute方法,该方法首先调用buildCommand方法构建作业提交所需的JSON参数,然后通过LivyCommandProcess的post2LivyWithRetry方法将作业提交到Livy服务器。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Executor as "LivyEngineExecutor" +participant CommandProcess as "LivyCommandProcess" +participant Helper as "LivyTaskSubmitHelper" +participant LivyServer as "Livy服务器" +Client->>Executor : execute() +Executor->>Executor : buildCommand() +Executor->>CommandProcess : post2LivyWithRetry() +CommandProcess->>Helper : postToLivy() +Helper->>LivyServer : POST /batches +LivyServer-->>Helper : 201 Created +Helper-->>CommandProcess : 返回结果 +CommandProcess-->>Executor : 返回会话ID +Executor->>CommandProcess : processResultOfLivyState() +CommandProcess->>Helper : getResultByLivyId() +Helper->>LivyServer : GET /batches/{id} +LivyServer-->>Helper : 返回状态 +Helper-->>CommandProcess : 解析状态 +loop 状态轮询 +CommandProcess->>Helper : 轮询状态 +Helper->>LivyServer : GET /batches/{id} +LivyServer-->>Helper : 返回状态 +alt 状态为SUCCESS +CommandProcess-->>Executor : 返回成功 +break +else 状态为ERROR/DEAD/KILLED +CommandProcess-->>Executor : 返回失败 +break +else 其他状态 +CommandProcess->>CommandProcess : 继续轮询 +end +end +``` + +**图源** +- [LivyEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java#L59-L78) +- [LivyCommandProcess.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L71-L120) +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L113-L164) + +**本文档引用的文件** +- [LivyEngineExecutor.java](file://datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [LivyCommandProcess.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) + +## Livy连接配置与会话管理 + +Livy执行引擎的连接配置和会话管理策略通过配置文件和代码实现相结合的方式进行管理。连接配置主要通过Configurations对象从系统配置中获取,关键配置项包括Livy服务器地址、Kerberos认证信息、代理用户等。会话管理则通过Livy的REST API实现,包括会话的创建、状态查询和终止等操作。 + +Livy连接配置主要包含以下关键参数: +- `livy.uri`: Livy服务器的REST API地址 +- `livy.need.kerberos`: 是否需要Kerberos认证 +- `livy.server.auth.kerberos.principal`: Kerberos认证的principal +- `livy.server.auth.kerberos.keytab`: Kerberos认证的keytab文件路径 +- `livy.task.proxyUser`: 作业提交的代理用户 +- `livy.task.appId.retry.count`: 获取应用ID的重试次数 + +```mermaid +flowchart TD +Start([开始]) --> Init["初始化LivyTaskSubmitHelper"] +Init --> GetConfig["从Configurations获取Livy配置"] +GetConfig --> CheckKerberos{"需要Kerberos认证?"} +CheckKerberos --> |是| SetupKerberos["创建KerberosRestTemplate"] +CheckKerberos --> |否| SetupNormal["创建普通RestTemplate"] +SetupKerberos --> ConfigureTemplate["配置RestTemplate"] +SetupNormal --> ConfigureTemplate +ConfigureTemplate --> SetHeaders["设置HTTP头(X-Requested-By)"] +SetHeaders --> Complete["初始化完成"] +Complete --> End([结束]) +``` + +**图源** +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L54-L65) +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L113-L164) + +**本文档引用的文件** +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L864-L872) + +## 任务状态监控与结果获取 + +Livy执行引擎通过轮询机制监控任务状态并获取执行结果。状态监控的核心是LivyCommandProcess的processResultOfLivyState方法,该方法通过LivyTaskSubmitHelper定期查询Livy会话的状态,直到作业完成或失败。LivyStates枚举类定义了所有可能的会话状态,包括NOT_STARTED、STARTING、IDLE、RUNNING、BUSY、SHUTTING_DOWN、ERROR、DEAD、KILLED、SUCCESS等。 + +任务状态监控流程如下: +1. 作业提交后,获取Livy会话ID +2. 启动状态轮询循环,定期查询会话状态 +3. 根据返回的状态码判断作业执行情况 +4. 如果状态为SUCCESS,则获取应用ID并标记作业成功 +5. 如果状态为ERROR、DEAD、KILLED或UNKNOWN,则标记作业失败 +6. 如果状态为其他中间状态,则继续轮询 + +```mermaid +stateDiagram-v2 +[*] --> 初始化 +初始化 --> 提交作业 : execute() +提交作业 --> 状态轮询 : 获取会话ID +状态轮询 --> 成功 : 状态为SUCCESS +状态轮询 --> 失败 : 状态为ERROR/DEAD/KILLED/UNKNOWN +状态轮询 --> 继续轮询 : 状态为RUNNING/BUSY等 +继续轮询 --> 状态轮询 : 延迟后继续查询 +成功 --> [*] +失败 --> [*] +``` + +**图源** +- [LivyCommandProcess.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java#L87-L119) +- [LivyStates.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java#L30-L47) + +**本文档引用的文件** +- [LivyCommandProcess.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java) +- [LivyStates.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java) + +## 故障排查指南 + +Livy执行引擎的故障排查主要涉及连接问题、认证问题、作业提交失败和状态监控异常等。以下是常见问题的排查指南: + +### 连接问题 +当出现连接Livy服务器失败时,应检查以下几点: +1. 确认`livy.uri`配置正确,包括协议、主机名、端口和路径 +2. 检查网络连通性,确保客户端可以访问Livy服务器 +3. 验证Livy服务器是否正常运行 + +### 认证问题 +当出现Kerberos认证失败时,应检查以下几点: +1. 确认`livy.need.kerberos`配置正确 +2. 验证`livy.server.auth.kerberos.principal`和`livy.server.auth.kerberos.keytab`配置正确 +3. 检查keytab文件是否存在且可读 +4. 验证Kerberos票据是否有效 + +### 作业提交失败 +当作业提交失败时,应检查以下几点: +1. 检查作业参数是否正确,特别是jar包路径和main class +2. 验证HDFS上的jar包是否存在 +3. 检查资源配额是否足够 +4. 查看Livy服务器日志获取详细错误信息 + +### 状态监控异常 +当状态监控出现异常时,应检查以下几点: +1. 确认会话ID是否正确获取 +2. 检查`livy.task.appId.retry.count`配置是否合理 +3. 验证Livy服务器状态查询接口是否正常 +4. 检查网络延迟是否导致轮询超时 + +**本文档引用的文件** +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) +- [LivyCommandProcess.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java) + +## 性能优化建议 + +为了提高Livy执行引擎的性能和可靠性,建议采取以下优化措施: + +### 配置优化 +1. **重试机制**: 合理设置`livy.task.appId.retry.count`参数,建议设置为3-5次,以应对网络波动导致的临时失败 +2. **轮询间隔**: 调整状态轮询的间隔时间,避免过于频繁的请求对Livy服务器造成压力 +3. **连接池**: 使用连接池管理HTTP连接,减少连接建立的开销 + +### 资源管理 +1. **资源预估**: 合理配置executor数量、core数量和内存大小,避免资源浪费或不足 +2. **JAR包管理**: 将常用的JAR包预先上传到HDFS,避免每次作业都上传 +3. **代理用户**: 使用合适的代理用户,避免权限问题导致的作业失败 + +### 错误处理 +1. **优雅降级**: 当Livy服务器不可用时,可以考虑降级到YARN直接提交模式 +2. **超时处理**: 设置合理的作业执行超时时间,避免长时间挂起 +3. **日志记录**: 完善日志记录,便于问题排查和性能分析 + +**本文档引用的文件** +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) +- [LivyCommandProcess.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/LivyCommandProcess.java) + +## 高可用与安全认证 + +Livy执行引擎支持高可用配置和多种安全认证机制,确保在生产环境中的稳定运行和数据安全。 + +### 高可用配置 +1. **Livy集群**: 部署Livy集群,通过负载均衡实现高可用 +2. **故障转移**: 当主Livy服务器不可用时,自动切换到备用服务器 +3. **会话持久化**: 配置Livy的会话持久化,确保服务器重启后会话不丢失 + +### 安全认证 +Livy执行引擎支持两种主要的认证方式: + +#### Kerberos认证 +Kerberos是一种网络认证协议,提供强身份验证。配置Kerberos认证需要: +1. 设置`livy.need.kerberos`为true +2. 配置`livy.server.auth.kerberos.principal`和`livy.server.auth.kerberos.keytab` +3. 确保客户端和服务器都在同一个Kerberos域中 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant KDC as "KDC" +participant Livy as "Livy服务器" +Client->>KDC : 请求TGT +KDC-->>Client : 返回加密的TGT +Client->>Livy : 请求服务票据 +Livy->>KDC : 验证TGT +KDC-->>Livy : 返回服务票据 +Livy-->>Client : 返回服务票据 +Client->>Livy : 使用服务票据访问API +Livy-->>Client : 返回响应 +``` + +**图源** +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L113-L164) + +#### 代理用户机制 +代理用户机制允许一个用户代表另一个用户执行操作。配置代理用户需要: +1. 设置`livy.task.proxyUser`参数 +2. 确保Livy服务器配置了允许的代理用户列表 +3. 验证代理用户的权限 + +**本文档引用的文件** +- [LivyTaskSubmitHelper.java](file://datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L866-L870) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/Spark\346\211\247\350\241\214\345\274\225\346\223\216.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/Spark\346\211\247\350\241\214\345\274\225\346\223\216.md" new file mode 100644 index 00000000..ddf04dc7 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/Spark\346\211\247\350\241\214\345\274\225\346\223\216.md" @@ -0,0 +1,278 @@ +# Spark执行引擎 + + +**本文档引用的文件** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java) +- [SparkSingleTableMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSingleTableMetricBuilder.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\SparkRuntimeEnvironment.java) +- [SparkBatchExecution.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\batch\SparkBatchExecution.java) +- [SparkDataVinesBootstrap.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-core\src\main\java\io\datavines\engine\spark\core\SparkDataVinesBootstrap.java) +- [JdbcSource.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-connector-jdbc\src\main\java\io\datavines\engine\spark\jdbc\source\JdbcSource.java) +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java) +- [SparkConstants.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkConstants.java) +- [SparkVersion.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkVersion.java) +- [ProgramType.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\ProgramType.java) + + +## 目录 +1. [任务提交机制](#任务提交机制) +2. [Spark参数配置](#spark参数配置) +3. [配置构建器](#配置构建器) +4. [运行时环境](#运行时环境) +5. [资源分配与性能优化](#资源分配与性能优化) +6. [Spark Connector](#spark-connector) + +## 任务提交机制 + +Spark执行引擎通过`SparkEngineExecutor`类实现任务提交机制。该机制基于YARN平台,通过构建spark-submit命令来提交Spark作业。执行器首先初始化作业请求和日志记录器,然后构建完整的命令行参数,最后通过ShellCommandProcess执行命令。 + +任务提交流程如下: +1. 初始化执行环境,设置线程名称和日志信息 +2. 解析引擎参数和应用参数 +3. 构建spark-submit命令行 +4. 执行命令并获取处理结果 +5. 记录执行过程和结果 + +```mermaid +sequenceDiagram +participant Executor as SparkEngineExecutor +participant Shell as ShellCommandProcess +participant YARN as YARN集群 +Executor->>Executor : init(初始化) +Executor->>Executor : buildCommand(构建命令) +Executor->>Shell : run(执行命令) +Shell->>YARN : 提交Spark作业 +YARN-->>Shell : 返回执行结果 +Shell-->>Executor : processResult +Executor->>Executor : 记录日志 +``` + +**图示来源** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java#L41-L152) + +**本节来源** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java#L41-L152) + +## Spark参数配置 + +Spark参数配置通过`SparkParameters`类定义,包含Spark作业所需的各种配置参数。这些参数在任务提交时被转换为spark-submit命令行参数。 + +主要配置参数包括: +- **主JAR包**: 指定要执行的主JAR文件路径 +- **主类**: 指定主类名称 +- **部署模式**: cluster或client模式 +- **资源配置**: 驱动程序和执行器的CPU核心数、内存大小 +- **应用配置**: 应用名称、队列、其他参数 +- **程序类型**: JAVA、SCALA或PYTHON +- **Spark版本**: SPARK2或SPARK3 + +```mermaid +classDiagram +class SparkParameters { ++String mainJar ++String mainClass ++String deployMode ++String mainArgs ++int driverCores ++String driverMemory ++int numExecutors ++int executorCores ++String executorMemory ++String appName ++String queue ++String others ++ProgramType programType ++String sparkVersion ++String jars ++checkParameters() boolean +} +class ProgramType { ++JAVA ++SCALA ++PYTHON +} +class SparkVersion { ++SPARK2 ++SPARK3 +} +SparkParameters --> ProgramType : "包含" +SparkParameters --> SparkVersion : "包含" +``` + +**图示来源** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java#L19-L219) +- [ProgramType.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\ProgramType.java#L19-L27) +- [SparkVersion.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkVersion.java#L19-L43) + +**本节来源** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java#L19-L219) + +## 配置构建器 + +Spark配置构建器负责为不同类型的质量检查生成作业配置。`BaseSparkConfigurationBuilder`是所有Spark配置构建器的基类,提供了通用的配置构建逻辑。 + +配置构建流程: +1. 获取环境配置 +2. 构建数据源配置 +3. 构建目标配置 +4. 构建转换配置 + +对于单表质量检查,`SparkSingleTableMetricBuilder`构建器会生成相应的配置,包括实际值存储、任务结果存储和错误数据存储的配置。 + +```mermaid +flowchart TD +Start([开始]) --> GetEnvConfig["获取环境配置"] +GetEnvConfig --> GetSourceConfigs["构建数据源配置"] +GetSourceConfigs --> GetSinkConfigs["构建目标配置"] +GetSinkConfigs --> GetTransformConfigs["构建转换配置"] +GetTransformConfigs --> End([完成]) +subgraph "单表质量检查配置" +GetSinkConfigs --> ActualValue["实际值存储配置"] +GetSinkConfigs --> TaskResult["任务结果存储配置"] +GetSinkConfigs --> ErrorData["错误数据存储配置"] +end +``` + +**图示来源** +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java#L47-L356) +- [SparkSingleTableMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSingleTableMetricBuilder.java#L35-L81) + +**本节来源** +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java#L47-L356) +- [SparkSingleTableMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSingleTableMetricBuilder.java#L35-L81) + +## 运行时环境 + +Spark运行时环境由`SparkRuntimeEnvironment`类管理,负责Spark会话的初始化和管理。环境初始化时会根据配置创建SparkSession,并根据需要启用Hive支持。 + +运行时环境的主要功能: +- 创建和管理SparkSession +- 支持Hive集成 +- 管理StreamingContext +- 提供执行环境 + +```mermaid +classDiagram +class SparkRuntimeEnvironment { +-SparkSession sparkSession +-StreamingContext streamingContext +-Config config +-boolean enableSparkHiveSupport ++setConfig(Config) void ++getConfig() Config ++checkConfig() CheckResult ++prepare() void ++sparkSession() SparkSession ++streamingContext() StreamingContext ++enableSparkHiveSupport() boolean ++getExecution() Execution +} +class SparkBatchExecution { +-SparkRuntimeEnvironment environment ++execute(List, List, List) void ++stop() void +} +SparkRuntimeEnvironment --> SparkBatchExecution : "创建" +SparkRuntimeEnvironment --> SparkSession : "包含" +SparkRuntimeEnvironment --> StreamingContext : "包含" +``` + +**图示来源** +- [SparkRuntimeEnvironment.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\SparkRuntimeEnvironment.java#L34-L117) +- [SparkBatchExecution.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\batch\SparkBatchExecution.java#L36-L136) + +**本节来源** +- [SparkRuntimeEnvironment.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\SparkRuntimeEnvironment.java#L34-L117) +- [SparkBatchExecution.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\batch\SparkBatchExecution.java#L36-L136) + +## 资源分配与性能优化 + +Spark执行引擎的资源分配策略通过`SparkArgsUtils`工具类实现,将配置参数转换为spark-submit命令行参数。资源分配包括驱动程序和执行器的CPU核心数、内存大小等。 + +性能优化建议: +1. **合理设置执行器数量**: 根据集群资源和任务复杂度调整num-executors +2. **优化内存分配**: 为驱动程序和执行器分配适当的内存 +3. **调整核心数**: 根据任务并行度需求设置executor-cores +4. **使用合适的部署模式**: cluster模式适合生产环境,client模式适合调试 +5. **启用Hive支持**: 当需要访问Hive表时启用spark-hive支持 + +```mermaid +flowchart LR +A[资源分配策略] --> B[驱动程序配置] +A --> C[执行器配置] +A --> D[应用配置] +B --> B1[driver-cores] +B --> B2[driver-memory] +C --> C1[num-executors] +C --> C2[executor-cores] +C --> C3[executor-memory] +D --> D1[app-name] +D --> D2[queue] +D --> D3[deploy-mode] +``` + +**图示来源** +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java#L25-L130) +- [SparkConstants.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkConstants.java#L19-L75) + +**本节来源** +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java#L25-L130) +- [SparkConstants.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkConstants.java#L19-L75) + +## Spark Connector + +Spark Connector支持多种数据源类型,通过插件机制实现。JDBC连接器是其中的重要组成部分,支持通过JDBC协议访问各种关系型数据库。 + +支持的数据源类型: +- ClickHouse +- Databend +- DM数据库 +- Doris +- 文件系统 +- Flink +- Hive +- Impala +- JDBC通用连接器 +- MongoDB +- MySQL +- Oracle +- PostgreSQL +- Presto +- Spark +- SQL Server +- StarRocks +- Trino + +JDBC连接器实现通过`JdbcSource`类提供数据读取功能,支持标准JDBC参数配置,包括URL、用户名、密码、驱动类等。 + +```mermaid +classDiagram +class JdbcSource { +-Config config ++setConfig(Config) void ++getConfig() Config ++checkConfig() CheckResult ++prepare(RuntimeEnvironment) void ++getData(SparkRuntimeEnvironment) Dataset +-hiveSourceData(SparkRuntimeEnvironment) Dataset +} +class SparkBatchSource { +<> ++setConfig(Config) void ++getConfig() Config ++checkConfig() CheckResult ++prepare(RuntimeEnvironment) void ++getData(SparkRuntimeEnvironment) Dataset +} +JdbcSource --|> SparkBatchSource : "实现" +``` + +**图示来源** +- [JdbcSource.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-connector-jdbc\src\main\java\io\datavines\engine\spark\jdbc\source\JdbcSource.java#L38-L117) +- [SparkBatchSource.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\batch\SparkBatchSource.java) + +**本节来源** +- [JdbcSource.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-connector-jdbc\src\main\java\io\datavines\engine\spark\jdbc\source\JdbcSource.java#L38-L117) +- [datavines-connector-plugins](file://datavines-connector\datavines-connector-plugins) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266.md" new file mode 100644 index 00000000..d4d758ae --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266.md" @@ -0,0 +1,473 @@ +# 执行引擎插件 + + +**本文档引用文件** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [FlinkDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-core/src/main/java/io/datavines/engine/flink/core/FlinkDataVinesBootstrap.java) +- [SparkDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-core/src/main/java/io/datavines/engine/spark/core/SparkDataVinesBootstrap.java) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + + +## 目录 +1. [执行引擎插件架构](#执行引擎插件架构) +2. [Flink执行引擎](#flink执行引擎) +3. [Spark执行引擎](#spark执行引擎) +4. [Livy执行引擎](#livy执行引擎) +5. [本地执行引擎](#本地执行引擎) +6. [性能与资源对比](#性能与资源对比) +7. [插件加载机制](#插件加载机制) +8. [配置参数说明](#配置参数说明) +9. [性能调优指南](#性能调优指南) +10. [新引擎开发模板](#新引擎开发模板) +11. [测试验证流程](#测试验证流程) + +## 执行引擎插件架构 + +DataVines平台的执行引擎插件系统采用基于SPI(Service Provider Interface)的插件化架构设计,实现了执行引擎的可扩展性和灵活性。系统通过统一的接口定义和抽象基类,支持Flink、Spark、Livy和本地四种执行引擎的集成。 + +核心架构由三个关键接口组成:`EngineExecutor`、`RuntimeEnvironment`和`Plugin`。`EngineExecutor`接口定义了执行引擎的生命周期方法,包括初始化、执行、后处理和取消等操作。`RuntimeEnvironment`接口定义了运行时环境的准备和执行上下文获取。`Plugin`接口则提供了配置设置、获取和验证的基础能力。 + +```mermaid +classDiagram +class EngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++cancel() void ++isCancel() boolean ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest +} +class Plugin { ++setConfig(Config) void ++getConfig() Config ++checkConfig() CheckResult +} +class RuntimeEnvironment { ++prepare() void ++getExecution() Execution +} +class AbstractEngineExecutor { +-jobExecutionRequest JobExecutionRequest +-logger Logger +-cancel boolean +-processResult ProcessResult ++logHandle(String[]) void ++isCancel() boolean +-buildCommand() String +} +class AbstractYarnEngineExecutor { +-shellCommandProcess ShellCommandProcess ++cancel() void +-killYarnApplication() void +} +class AbstractLivyEngineExecutor { +-livyCommandProcess LivyCommandProcess ++cancel() void +} +EngineExecutor <|-- AbstractEngineExecutor +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +AbstractEngineExecutor <|-- AbstractLivyEngineExecutor +AbstractYarnEngineExecutor <|-- FlinkEngineExecutor +AbstractYarnEngineExecutor <|-- SparkEngineExecutor +AbstractEngineExecutor <|-- LocalEngineExecutor +AbstractLivyEngineExecutor <|-- LivyEngineExecutor +Plugin <|-- EngineExecutor +RuntimeEnvironment <|-- Plugin +``` + +**图源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) + +**本节来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L26-L42) +- [Plugin.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/plugin/Plugin.java#L24-L31) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java#L23-L28) + +## Flink执行引擎 + +Flink执行引擎通过`FlinkEngineExecutor`类实现,继承自`AbstractYarnEngineExecutor`,采用YARN集群模式运行Flink作业。该引擎通过构建Flink命令行来提交作业,利用Flink的分布式流处理能力进行数据质量检查。 + +`FlinkEngineExecutor`的执行流程包括:初始化时设置日志线程名称和命令行处理器;执行时通过`buildCommand`方法构建完整的Flink命令;执行完成后进行资源清理。在`buildCommand`方法中,系统会解析Flink参数,设置主JAR包路径、主类名和运行参数,并将作业配置序列化为Base64编码的字符串作为参数传递。 + +Flink引擎的作业启动通过调用Flink的`bin/flink`脚本实现,使用`flink run`命令提交作业。作业的主类为`io.datavines.engine.flink.core.FlinkDataVinesBootstrap`,该类负责启动Flink流处理作业并执行数据质量检查逻辑。 + +```mermaid +sequenceDiagram +participant JobRunner +participant FlinkEngineExecutor +participant ShellCommandProcess +participant FlinkCluster +JobRunner->>FlinkEngineExecutor : init() +FlinkEngineExecutor->>FlinkEngineExecutor : 设置日志线程名称 +FlinkEngineExecutor->>FlinkEngineExecutor : 初始化ShellCommandProcess +JobRunner->>FlinkEngineExecutor : execute() +FlinkEngineExecutor->>FlinkEngineExecutor : buildCommand() +FlinkEngineExecutor->>FlinkEngineExecutor : 构建Flink命令行 +FlinkEngineExecutor->>ShellCommandProcess : run(command) +ShellCommandProcess->>FlinkCluster : 提交Flink作业 +FlinkCluster-->>ShellCommandProcess : 返回执行结果 +ShellCommandProcess-->>FlinkEngineExecutor : processResult +FlinkEngineExecutor-->>JobRunner : 返回执行结果 +JobRunner->>FlinkEngineExecutor : cancel() +FlinkEngineExecutor->>FlinkEngineExecutor : killYarnApplication() +FlinkEngineExecutor->>ShellCommandProcess : cancel() +FlinkEngineExecutor->>FlinkCluster : 终止YARN应用 +``` + +**图源** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) + +**本节来源** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L38-L182) +- [FlinkDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-core/src/main/java/io/datavines/engine/flink/core/FlinkDataVinesBootstrap.java#L25-L36) + +## Spark执行引擎 + +Spark执行引擎通过`SparkEngineExecutor`类实现,同样继承自`AbstractYarnEngineExecutor`,采用YARN集群模式运行Spark作业。该引擎通过构建Spark-submit命令来提交作业,利用Spark的批处理能力进行数据质量检查。 + +`SparkEngineExecutor`的执行流程与Flink引擎类似,但在命令构建方面有所不同。系统会解析Spark参数,设置主JAR包路径、主类名和运行参数。与Flink引擎不同的是,Spark引擎会自动扫描插件目录下的JAR文件,并将其添加到`--jars`参数中,确保所有依赖都能正确加载。 + +Spark引擎的作业启动通过调用`SPARK2_COMMAND`(即`spark-submit`)实现。作业的主类为`io.datavines.engine.spark.core.SparkDataVinesBootstrap`,该类负责启动Spark应用程序并执行数据质量检查逻辑。系统还会在Spark配置中添加作业唯一ID作为标签,便于作业追踪和管理。 + +```mermaid +sequenceDiagram +participant JobRunner +participant SparkEngineExecutor +participant ShellCommandProcess +participant SparkCluster +JobRunner->>SparkEngineExecutor : init() +SparkEngineExecutor->>SparkEngineExecutor : 设置日志线程名称 +SparkEngineExecutor->>SparkEngineExecutor : 初始化ShellCommandProcess +JobRunner->>SparkEngineExecutor : execute() +SparkEngineExecutor->>SparkEngineExecutor : buildCommand() +SparkEngineExecutor->>SparkEngineExecutor : 构建Spark-submit命令 +SparkEngineExecutor->>SparkEngineExecutor : 扫描插件JAR文件 +SparkEngineExecutor->>ShellCommandProcess : run(command) +ShellCommandProcess->>SparkCluster : 提交Spark作业 +SparkCluster-->>ShellCommandProcess : 返回执行结果 +ShellCommandProcess-->>SparkEngineExecutor : processResult +SparkEngineExecutor-->>JobRunner : 返回执行结果 +JobRunner->>SparkEngineExecutor : cancel() +SparkEngineExecutor->>SparkEngineExecutor : killYarnApplication() +SparkEngineExecutor->>ShellCommandProcess : cancel() +SparkEngineExecutor->>SparkCluster : 终止YARN应用 +``` + +**图源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [SparkDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-core/src/main/java/io/datavines/engine/spark/core/SparkDataVinesBootstrap.java) + +**本节来源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L152) +- [SparkDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-core/src/main/java/io/datavines/engine/spark/core/SparkDataVinesBootstrap.java#L23-L33) + +## Livy执行引擎 + +Livy执行引擎通过`LivyEngineExecutor`类实现,继承自`AbstractLivyEngineExecutor`,采用Livy REST API提交Spark作业。该引擎不直接执行命令,而是通过HTTP请求与Livy服务器通信来管理Spark作业的生命周期。 + +`LivyEngineExecutor`的执行流程包括:初始化时创建`LivyCommandProcess`用于处理HTTP请求;执行时通过`buildCommand`方法构建JSON格式的Livy请求体;然后调用`post2LivyWithRetry`方法向Livy服务器提交作业;最后监控作业状态并获取执行结果。 + +Livy引擎的作业提交采用RESTful API方式,请求体包含作业的JAR文件路径、主类名、参数、资源分配等配置。系统会将数据质量检查配置序列化为JSON字符串,并作为作业参数传递。作业提交后,Livy服务器会返回作业ID,引擎会持续轮询作业状态直到完成。 + +```mermaid +sequenceDiagram +participant JobRunner +participant LivyEngineExecutor +participant LivyCommandProcess +participant LivyServer +participant SparkCluster +JobRunner->>LivyEngineExecutor : init() +LivyEngineExecutor->>LivyEngineExecutor : 设置日志线程名称 +LivyEngineExecutor->>LivyEngineExecutor : 初始化LivyCommandProcess +JobRunner->>LivyEngineExecutor : execute() +LivyEngineExecutor->>LivyEngineExecutor : buildCommand() +LivyEngineExecutor->>LivyEngineExecutor : 构建Livy JSON请求 +LivyEngineExecutor->>LivyCommandProcess : post2LivyWithRetry() +LivyCommandProcess->>LivyServer : POST /sessions +LivyServer-->>LivyCommandProcess : 返回会话ID +LivyCommandProcess->>LivyServer : 轮询作业状态 +LivyServer-->>LivyCommandProcess : 返回作业状态 +LivyCommandProcess->>LivyEngineExecutor : processResultOfLivyState() +LivyEngineExecutor-->>JobRunner : 返回执行结果 +JobRunner->>LivyEngineExecutor : cancel() +LivyEngineExecutor->>LivyCommandProcess : cancel() +LivyCommandProcess->>LivyServer : 终止会话 +``` + +**图源** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) + +**本节来源** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java#L42-L236) +- [SparkDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-core/src/main/java/io/datavines/engine/spark/core/SparkDataVinesBootstrap.java) + +## 本地执行引擎 + +本地执行引擎通过`LocalEngineExecutor`类实现,继承自`AbstractEngineExecutor`,在本地JVM进程中直接执行数据质量检查任务。该引擎适用于开发测试和小规模数据处理场景,无需依赖外部计算集群。 + +`LocalEngineExecutor`的执行流程包括:初始化时设置日志信息;执行时创建`LocalDataVinesBootstrap`实例并调用其`execute`方法;执行完成后进行清理。与分布式引擎不同,本地引擎不构建外部命令,而是直接在当前JVM中启动数据质量检查流程。 + +本地引擎的作业执行通过`LocalDataVinesBootstrap`类实现,该类继承自`BaseDataVinesBootstrap`,负责解析配置并执行相应的数据质量检查逻辑。系统会将作业配置作为参数传递给引导类,由引导类负责整个执行流程的协调和管理。 + +```mermaid +sequenceDiagram +participant JobRunner +participant LocalEngineExecutor +participant LocalDataVinesBootstrap +JobRunner->>LocalEngineExecutor : init() +LocalEngineExecutor->>LocalEngineExecutor : 设置日志信息 +LocalEngineExecutor->>LocalEngineExecutor : 设置线程名称 +JobRunner->>LocalEngineExecutor : execute() +LocalEngineExecutor->>LocalEngineExecutor : 创建LocalDataVinesBootstrap +LocalEngineExecutor->>LocalDataVinesBootstrap : execute(args) +LocalDataVinesBootstrap->>LocalDataVinesBootstrap : 解析配置 +LocalDataVinesBootstrap->>LocalDataVinesBootstrap : 执行数据质量检查 +LocalDataVinesBootstrap-->>LocalEngineExecutor : 返回执行结果 +LocalEngineExecutor-->>JobRunner : 返回执行结果 +JobRunner->>LocalEngineExecutor : cancel() +LocalEngineExecutor->>LocalDataVinesBootstrap : stop() +LocalEngineExecutor->>LocalEngineExecutor : 设置cancel标志 +``` + +**图源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) + +**本节来源** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L27-L77) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java#L23-L28) + +## 性能与资源对比 + +四种执行引擎在性能、资源利用率和功能支持方面各有特点,适用于不同的应用场景。以下是对各引擎的详细对比分析: + +| 特性 | Flink引擎 | Spark引擎 | Livy引擎 | 本地引擎 | +|------|---------|---------|--------|-------| +| **执行模式** | 流处理 | 批处理 | 批处理 | 本地执行 | +| **延迟** | 低(秒级) | 高(分钟级) | 高(分钟级) | 低(秒级) | +| **吞吐量** | 高 | 高 | 高 | 低 | +| **资源开销** | 中等 | 高 | 高 | 低 | +| **启动时间** | 中等 | 长 | 长 | 短 | +| **容错能力** | 强 | 中等 | 中等 | 弱 | +| **状态管理** | 支持 | 有限支持 | 有限支持 | 不支持 | +| **窗口计算** | 原生支持 | 通过结构化流支持 | 不支持 | 不支持 | +| **背压处理** | 原生支持 | 有限支持 | 不支持 | 不支持 | +| **集群依赖** | Flink集群 | Spark集群 | Livy服务器 | 无 | +| **适用场景** | 实时数据质量监控 | 大规模批处理 | 共享Spark集群 | 开发测试 | + +Flink引擎在实时性方面表现最佳,适合需要低延迟响应的数据质量监控场景。其流处理架构能够实现秒级甚至毫秒级的数据质量检查,同时具备强大的状态管理和容错能力。然而,Flink集群的维护成本相对较高,且对开发人员的技术要求较高。 + +Spark引擎在大规模批处理场景下表现出色,适合处理TB级以上的数据质量检查任务。其基于内存的计算模型能够提供较高的处理速度,但作业启动时间较长,不适合实时性要求高的场景。Spark引擎的生态系统丰富,易于与其他大数据工具集成。 + +Livy引擎提供了对Spark集群的RESTful访问接口,适合多租户环境和共享集群场景。通过Livy服务器,多个客户端可以安全地提交和管理Spark作业,而无需直接访问集群。这种架构提高了资源利用率和安全性,但增加了额外的网络开销和延迟。 + +本地引擎在资源利用率方面最优,无需额外的集群资源,适合开发测试和小规模数据处理。其启动速度快,调试方便,但受限于单机性能,不适合处理大规模数据。本地引擎是快速验证数据质量规则的理想选择。 + +**本节来源** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) + +## 插件加载机制 + +DataVines平台的插件加载机制基于自定义的SPI(Service Provider Interface)框架实现,位于`datavines-spi`模块中。该机制通过`PluginLoader`类提供插件的发现、加载和管理功能,实现了执行引擎的动态扩展能力。 + +插件加载的核心流程如下:首先,系统通过`PluginLoader.getPluginLoader(Class type)`方法获取指定接口类型的插件加载器;然后,加载器会扫描类路径下的`META-INF/plugins/`目录,查找与接口名称匹配的配置文件;接着,解析配置文件中的类名映射,加载对应的实现类;最后,通过反射创建插件实例并进行缓存管理。 + +插件配置文件采用标准的Java SPI格式,每行包含一个插件名称和实现类的映射,格式为`name=fully.qualified.class.name`。系统会自动发现所有实现了`EngineExecutor`接口的插件,并根据名称进行管理和调用。这种设计使得新增执行引擎只需添加相应的实现类和配置文件,无需修改核心代码。 + +```mermaid +flowchart TD +Start([开始]) --> GetPluginLoader["获取PluginLoader实例"] +GetPluginLoader --> CheckCache{"缓存中存在?"} +CheckCache --> |是| ReturnCached["返回缓存实例"] +CheckCache --> |否| LoadClasses["加载插件类"] +LoadClasses --> FindDirectory["查找META-INF/plugins/目录"] +FindDirectory --> ReadFiles["读取接口配置文件"] +ReadFiles --> ParseLines["解析类名映射"] +ParseLines --> LoadClasses["通过反射加载类"] +LoadClasses --> CreateInstances["创建插件实例"] +CreateInstances --> CacheInstances["缓存实例"] +CacheInstances --> ReturnInstance["返回插件实例"] +ReturnCached --> End([结束]) +ReturnInstance --> End +``` + +**图源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +**本节来源** +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L79-L407) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L26) + +## 配置参数说明 + +各执行引擎支持不同的配置参数,这些参数通过`JobExecutionRequest`对象传递,包括引擎特定参数和应用参数。以下是各引擎的主要配置参数说明: + +### Flink引擎配置参数 +- **主JAR包**: `data.quality.flink.jar.name` - 指定Flink作业的主JAR包名称 +- **FLINK_HOME**: 环境变量 - 指定Flink安装目录 +- **资源分配**: 包括TaskManager数量、Slot数量、内存配置等 +- **并行度**: 作业的并行执行度 +- **检查点**: 检查点间隔、超时时间、最小间隔等 +- **状态后端**: 状态存储类型(内存、文件系统、RocksDB) + +### Spark引擎配置参数 +- **主JAR包**: `data.quality.jar.name` - 指定Spark作业的主JAR包名称 +- **SPARK_HOME2**: 环境变量 - 指定Spark安装目录 +- **资源分配**: + - `driverCores`: Driver核心数 + - `driverMemory`: Driver内存 + - `numExecutors`: Executor数量 + - `executorCores`: 每个Executor的核心数 + - `executorMemory`: 每个Executor的内存 +- **队列**: `queue` - YARN队列名称 +- **其他参数**: `others` - 其他Spark配置参数 + +### Livy引擎配置参数 +- **主JAR包**: `data.quality.jar.name` - 指定Spark作业的主JAR包名称 +- **JAR库路径**: `livy.task.jar.lib.path` - HDFS上的JAR库路径 +- **附加JAR**: `livy.task.jars` - 需要加载的附加JAR文件列表 +- **代理用户**: `livy.task.proxyUser` - Livy代理用户 +- **资源分配**: 与Spark引擎类似,包括Driver和Executor的资源配置 +- **超时设置**: 会话超时时间、批处理超时时间等 + +### 本地引擎配置参数 +- **无特殊配置**: 本地引擎主要依赖JVM参数和系统资源 +- **日志配置**: 日志级别、输出格式等 +- **线程池**: 本地执行的线程池大小 + +**本节来源** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) + +## 性能调优指南 + +针对不同执行引擎的特性,以下是相应的性能调优建议: + +### Flink引擎调优 +1. **并行度优化**: 根据数据量和集群资源合理设置作业并行度,避免过度并行导致资源竞争 +2. **状态管理**: 选择合适的状态后端,对于大状态作业推荐使用RocksDB状态后端 +3. **检查点配置**: 根据业务需求平衡检查点频率和性能影响,避免过于频繁的检查点 +4. **内存调优**: 合理分配TaskManager的堆内存和堆外内存,避免GC压力过大 +5. **网络缓冲区**: 调整网络缓冲区大小以优化网络传输性能 + +### Spark引擎调优 +1. **资源分配**: 根据数据规模合理设置Executor数量和资源配置,避免资源浪费或不足 +2. **并行度**: 设置合适的分区数,确保数据均衡分布,避免数据倾斜 +3. **内存管理**: 调整Executor内存分配,合理设置堆内存和堆外内存比例 +4. **序列化**: 使用Kryo序列化提高序列化性能 +5. **数据本地性**: 优化数据存储位置,提高数据本地性,减少网络传输 + +### Livy引擎调优 +1. **会话管理**: 合理设置会话超时时间,平衡资源利用率和响应速度 +2. **批处理配置**: 优化批处理的资源配置,避免资源争用 +3. **连接池**: 配置Livy客户端连接池,提高并发处理能力 +4. **重试机制**: 设置合理的重试策略,应对网络波动和临时故障 +5. **监控告警**: 建立完善的监控体系,及时发现和处理作业异常 + +### 通用调优建议 +1. **数据分区**: 合理设计数据分区策略,提高数据处理效率 +2. **缓存策略**: 对频繁访问的数据进行缓存,减少重复计算 +3. **日志级别**: 生产环境使用适当的日志级别,避免过多日志影响性能 +4. **资源监控**: 实时监控作业的资源使用情况,及时发现性能瓶颈 +5. **基准测试**: 定期进行基准测试,评估调优效果并持续优化 + +**本节来源** +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) + +## 新引擎开发模板 + +开发新的执行引擎插件需要遵循以下模板和步骤: + +1. **创建Maven模块**: 在`datavines-engine-plugins`目录下创建新的模块,命名规范为`datavines-engine-{engine-name}` +2. **实现EngineExecutor接口**: 创建执行器类,继承`AbstractEngineExecutor`或其子类,实现所有抽象方法 +3. **添加SPI配置**: 在`src/main/resources/META-INF/plugins/`目录下创建配置文件,格式为`io.datavines.engine.api.engine.EngineExecutor` +4. **注册插件**: 在配置文件中添加插件名称和实现类的映射,格式为`engine-name=fully.qualified.class.name` +5. **实现核心逻辑**: 在`execute()`方法中实现具体的作业提交和执行逻辑 +6. **处理异常**: 完善异常处理机制,确保作业失败时能够正确报告错误信息 +7. **资源清理**: 在`after()`和`cancel()`方法中实现资源清理逻辑 +8. **日志记录**: 添加详细的日志记录,便于问题排查和监控 + +```mermaid +flowchart TD +Start([创建新引擎插件]) --> CreateModule["创建Maven模块\ndatavines-engine-{engine-name}"] +CreateModule --> ImplementInterface["实现EngineExecutor接口\n继承AbstractEngineExecutor"] +ImplementInterface --> AddSPIConfig["添加SPI配置文件\nMETA-INF/plugins/io.datavines.engine.api.engine.EngineExecutor"] +AddSPIConfig --> RegisterPlugin["注册插件\nengine-name=fully.qualified.class.name"] +RegisterPlugin --> ImplementCore["实现核心执行逻辑\nexecute()方法"] +ImplementCore --> HandleException["完善异常处理"] +HandleException --> CleanupResource["实现资源清理\nafter()和cancel()方法"] +CleanupResource --> AddLogging["添加详细日志"] +AddLogging --> TestPlugin["测试插件功能"] +TestPlugin --> End([完成]) +``` + +**图源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) + +**本节来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java#L26-L42) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java#L27-L56) + +## 测试验证流程 + +新执行引擎插件的测试验证应遵循以下流程: + +1. **单元测试**: 编写单元测试验证执行器的基本功能,包括初始化、执行、取消等操作 +2. **集成测试**: 在实际环境中测试引擎与平台的集成,验证作业提交、执行监控和结果返回 +3. **性能测试**: 进行基准测试,评估引擎在不同数据规模下的性能表现 +4. **边界测试**: 测试各种边界条件和异常情况,如网络中断、资源不足、配置错误等 +5. **兼容性测试**: 验证引擎在不同版本的依赖组件下的兼容性 +6. **安全测试**: 检查引擎的安全性,防止代码注入、权限提升等安全问题 +7. **文档更新**: 更新相关文档,包括配置说明、使用指南和故障排查 + +测试过程中应重点关注以下方面: +- 作业提交的正确性 +- 执行状态的准确监控 +- 错误信息的完整报告 +- 资源的正确清理 +- 性能指标的合理范围 +- 日志信息的完整性 + +```mermaid +flowchart TD +Start([开始测试]) --> UnitTest["单元测试\n验证基本功能"] +UnitTest --> IntegrationTest["集成测试\n验证平台集成"] +IntegrationTest --> PerformanceTest["性能测试\n基准测试"] +PerformanceTest --> BoundaryTest["边界测试\n异常情况"] +BoundaryTest --> CompatibilityTest["兼容性测试\n版本兼容"] +CompatibilityTest --> SecurityTest["安全测试\n漏洞检查"] +SecurityTest --> Documentation["文档更新"] +Documentation --> End([完成测试]) +``` + +**图源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) + +**本节来源** +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/\346\234\254\345\234\260\346\211\247\350\241\214\345\274\225\346\223\216.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/\346\234\254\345\234\260\346\211\247\350\241\214\345\274\225\346\223\216.md" new file mode 100644 index 00000000..a72ce0ac --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\211\247\350\241\214\345\274\225\346\223\216\346\217\222\344\273\266/\346\234\254\345\234\260\346\211\247\350\241\214\345\274\225\346\223\216.md" @@ -0,0 +1,298 @@ +# 本地执行引擎 + + +**本文档引用的文件** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java) +- [BaseJdbcSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSource.java) +- [ConnectionHolder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/entity/ConnectionHolder.java) + + +## 目录 +1. [简介](#简介) +2. [本地任务执行机制与进程管理](#本地任务执行机制与进程管理) +3. [本地配置构建器](#本地配置构建器) +4. [本地运行时环境](#本地运行时环境) +5. [配置参数与使用限制](#配置参数与使用限制) +6. [数据源连接与结果处理](#数据源连接与结果处理) +7. [总结](#总结) + +## 简介 + +本地执行引擎是 DataVines 框架中的一个重要组件,用于在本地环境中执行数据质量检查、数据剖析和数据对账等任务。该引擎通过 `LocalEngineExecutor` 类实现,支持从文件或 JDBC 数据源读取数据,并将结果写入指定的目标。本地执行模式适用于开发测试、小规模数据处理以及对资源消耗敏感的场景。 + +**本地执行引擎的核心特点包括:** +- **轻量级**:无需依赖外部集群,直接在本地 JVM 中运行。 +- **灵活性**:支持多种数据源(如文件、JDBC)和目标存储。 +- **易用性**:提供简单的配置接口,便于快速部署和调试。 +- **可扩展性**:基于插件化设计,可以轻松添加新的数据源和转换逻辑。 + +本文档详细介绍了 `LocalEngineExecutor` 的本地任务执行机制、进程管理、配置构建器、运行时环境、配置参数及使用限制,以及数据源连接和结果处理的实现细节。 + +## 本地任务执行机制与进程管理 + +`LocalEngineExecutor` 是本地执行引擎的核心类,继承自 `AbstractEngineExecutor`,负责初始化、执行和取消任务。其主要方法如下: + +- **init**:初始化任务执行请求,设置日志记录器和线程名称。 +- **execute**:执行任务,创建 `LocalDataVinesBootstrap` 实例并调用其 `execute` 方法。 +- **after**:任务执行后的清理工作。 +- **cancel**:取消任务,停止 `LocalDataVinesBootstrap` 并标记任务为已取消。 +- **getProcessResult**:获取任务执行结果。 +- **getTaskRequest**:获取任务请求信息。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Executor as "LocalEngineExecutor" +participant Bootstrap as "LocalDataVinesBootstrap" +Client->>Executor : init(jobExecutionRequest, logger, configurations) +Executor->>Executor : 设置线程名称 +Executor->>Executor : 保存任务请求和日志记录器 +Client->>Executor : execute() +Executor->>Executor : 创建参数数组 +Executor->>Executor : 初始化LocalDataVinesBootstrap +Executor->>Bootstrap : execute(args) +Bootstrap-->>Executor : 返回ProcessResult +Executor->>Executor : 保存执行结果 +Client->>Executor : cancel() +Executor->>Bootstrap : stop() +Executor->>Executor : 标记任务为已取消 +``` + +**本地任务执行流程:** +1. 客户端调用 `init` 方法,传入任务执行请求、日志记录器和配置。 +2. `LocalEngineExecutor` 初始化任务,设置线程名称,并保存相关对象。 +3. 客户端调用 `execute` 方法,`LocalEngineExecutor` 创建 `LocalDataVinesBootstrap` 实例并传递参数。 +4. `LocalDataVinesBootstrap` 执行任务,返回执行结果。 +5. 如果需要取消任务,客户端调用 `cancel` 方法,`LocalEngineExecutor` 停止 `LocalDataVinesBootstrap` 并标记任务为已取消。 + +**Section sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L27-L77) + +## 本地配置构建器 + +`BaseJobConfigurationBuilder` 是一个抽象类,实现了 `JobConfigurationBuilder` 接口,用于生成适用于本地执行的作业配置。它提供了以下方法: + +- **init**:初始化输入参数和任务执行信息,设置日期相关的占位符。 +- **buildName**:构建任务名称。 +- **buildEnvConfig**:构建环境配置。 +- **buildSourceConfigs**:构建数据源配置。 +- **buildTransformConfigs**:构建转换配置。 +- **buildSinkConfigs**:构建目标配置。 +- **build**:返回最终的 `DataVinesJobConfig` 对象。 + +```mermaid +classDiagram +class BaseJobConfigurationBuilder { ++Map inputParameter ++JobExecutionParameter jobExecutionParameter ++JobExecutionInfo jobExecutionInfo ++Map> metric2InputParameter ++init(Map, JobExecutionInfo) ++buildName() ++buildEnvConfig() ++buildSourceConfigs() ++buildTransformConfigs() ++buildSinkConfigs() ++build() DataVinesJobConfig +} +class JobConfigurationBuilder { +<> ++init(Map, JobExecutionInfo) ++buildName() ++buildEnvConfig() ++buildSourceConfigs() ++buildTransformConfigs() ++buildSinkConfigs() ++build() DataVinesJobConfig +} +BaseJobConfigurationBuilder --|> JobConfigurationBuilder +``` + +**本地配置构建流程:** +1. 调用 `init` 方法,传入输入参数和任务执行信息,设置日期相关的占位符。 +2. 调用 `buildName` 方法,设置任务名称。 +3. 调用 `buildEnvConfig` 方法,设置环境配置。 +4. 调用 `buildSourceConfigs` 方法,设置数据源配置。 +5. 调用 `buildTransformConfigs` 方法,设置转换配置。 +6. 调用 `buildSinkConfigs` 方法,设置目标配置。 +7. 调用 `build` 方法,返回最终的 `DataVinesJobConfig` 对象。 + +**Section sources** +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java#L45-L322) + +## 本地运行时环境 + +`LocalRuntimeEnvironment` 类实现了 `RuntimeEnvironment` 接口,提供了本地运行时环境的管理功能。它包含以下字段和方法: + +- **sourceConnection**:源数据源连接。 +- **targetConnection**:目标数据源连接。 +- **metadataConnection**:元数据连接。 +- **currentStatement**:当前 SQL 语句。 +- **stop**:是否停止执行。 +- **prepare**:准备执行环境。 +- **getExecution**:获取执行器。 +- **setConfig**:设置配置。 +- **getConfig**:获取配置。 +- **checkConfig**:检查配置。 +- **close**:关闭所有连接。 + +```mermaid +classDiagram +class LocalRuntimeEnvironment { ++ConnectionHolder sourceConnection ++ConnectionHolder targetConnection ++ConnectionHolder metadataConnection ++Statement currentStatement ++boolean stop ++prepare() ++getExecution() Execution ++setConfig(Config) ++getConfig() Config ++checkConfig() CheckResult ++close() void +} +class RuntimeEnvironment { +<> ++prepare() ++getExecution() Execution ++setConfig(Config) ++getConfig() Config ++checkConfig() CheckResult +} +LocalRuntimeEnvironment --|> RuntimeEnvironment +``` + +**本地运行时环境的特点:** +- **连接管理**:通过 `ConnectionHolder` 管理源、目标和元数据连接。 +- **执行控制**:提供 `stop` 字段,允许外部控制任务的停止。 +- **资源释放**:通过 `close` 方法确保所有连接和资源被正确释放。 + +**适用场景:** +- 开发和测试环境,快速验证数据处理逻辑。 +- 小规模数据处理,避免资源浪费。 +- 对延迟敏感的应用,减少网络传输开销。 + +**Section sources** +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java#L31-L99) + +## 配置参数与使用限制 + +### 配置参数 + +本地执行模式支持以下配置参数: + +- **path**:文件路径,用于读取本地文件。 +- **table_name**:表名,用于创建临时表。 +- **schema**:表结构,定义列名和类型。 +- **url**:JDBC 连接 URL。 +- **user**:数据库用户名。 +- **password**:数据库密码。 +- **database**:数据库名称。 +- **schema_name**:模式名称。 +- **table**:表名称。 +- **pre_sql**:前置 SQL 脚本,在数据处理前执行。 +- **post_sql**:后置 SQL 脚本,在数据处理后执行。 + +### 使用限制 + +- **文件大小限制**:文件长度不能超过 10MB,否则会抛出异常。 +- **并发限制**:不支持高并发执行,建议单线程运行。 +- **资源消耗**:由于在本地 JVM 中运行,可能会占用较多内存和 CPU 资源。 +- **网络依赖**:对于 JDBC 数据源,需要保证网络连接稳定。 + +**Section sources** +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java#L101-L107) +- [BaseJdbcSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSource.java#L62-L78) + +## 数据源连接与结果处理 + +### 数据源连接 + +`LocalFileSource` 和 `BaseJdbcSource` 分别实现了文件和 JDBC 数据源的连接。它们都实现了 `LocalSource` 接口,提供了以下方法: + +- **setConfig**:设置配置。 +- **getConfig**:获取配置。 +- **checkConfig**:检查配置是否完整。 +- **getConnectionItem**:获取连接项。 +- **prepare**:准备执行环境。 +- **checkTableExist**:检查表是否存在。 + +```mermaid +classDiagram +class LocalSource { +<> ++setConfig(Config) ++getConfig() Config ++checkConfig() CheckResult ++getConnectionItem(LocalRuntimeEnvironment) ConnectionHolder ++prepare(RuntimeEnvironment) ++checkTableExist() boolean +} +class LocalFileSource { ++setConfig(Config) ++getConfig() Config ++checkConfig() CheckResult ++getConnectionItem(LocalRuntimeEnvironment) ConnectionHolder ++prepare(RuntimeEnvironment) ++checkTableExist() boolean +} +class BaseJdbcSource { ++setConfig(Config) ++getConfig() Config ++checkConfig() CheckResult ++getConnectionItem(LocalRuntimeEnvironment) ConnectionHolder ++prepare(RuntimeEnvironment) ++checkTableExist() boolean +} +LocalFileSource --|> LocalSource +BaseJdbcSource --|> LocalSource +``` + +### 结果处理 + +`LocalExecution` 类负责执行数据处理任务,包括数据读取、转换和写入。它通过 `execute` 方法协调 `LocalSource`、`LocalTransform` 和 `LocalSink` 组件的工作。 + +```mermaid +flowchart TD +Start([开始]) --> Prepare["准备执行环境"] +Prepare --> CheckSources["检查数据源配置"] +CheckSources --> ReadData["读取数据"] +ReadData --> TransformData["转换数据"] +TransformData --> WriteData["写入结果"] +WriteData --> PostProcess["执行后置脚本"] +PostProcess --> CloseConnections["关闭连接"] +CloseConnections --> End([结束]) +style Start fill:#f9f,stroke:#333,stroke-width:2px +style End fill:#f9f,stroke:#333,stroke-width:2px +``` + +**数据源连接与结果处理流程:** +1. 准备执行环境,设置日志记录器和连接。 +2. 检查数据源配置,确保所有必需的参数都已提供。 +3. 读取数据,根据配置从文件或 JDBC 数据源加载数据。 +4. 转换数据,应用各种转换逻辑(如实际值计算、预期值生成等)。 +5. 写入结果,将处理后的数据写入目标存储。 +6. 执行后置脚本,清理临时资源。 +7. 关闭所有连接,释放资源。 + +**Section sources** +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java#L43-L143) +- [BaseJdbcSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSource.java#L40-L121) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java#L39-L201) + +## 总结 + +本地执行引擎是 DataVines 框架中的一个重要组成部分,提供了轻量级、灵活且易于使用的数据处理能力。通过 `LocalEngineExecutor`、`LocalRuntimeEnvironment` 和 `BaseJobConfigurationBuilder` 等核心组件,用户可以在本地环境中高效地执行数据质量检查、数据剖析和数据对账等任务。本文档详细介绍了这些组件的功能、配置参数、使用限制以及数据源连接和结果处理的实现细节,帮助开发者更好地理解和使用本地执行模式。 + +**Section sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java) +- [BaseJdbcSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-jdbc/src/main/java/io/datavines/engine/local/connector/BaseJdbcSource.java) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\240\270\345\277\203\345\274\225\346\223\216.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\240\270\345\277\203\345\274\225\346\223\216.md" new file mode 100644 index 00000000..86af4eb9 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-engine\346\250\241\345\235\227/\346\240\270\345\277\203\345\274\225\346\223\216.md" @@ -0,0 +1,237 @@ +# 核心引擎 + + +**本文档中引用的文件** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) +- [ParserUtils.java](file://datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/ParserUtils.java) +- [QuoteIdentifier.java](file://datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/QuoteIdentifier.java) +- [MetricParserUtils.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/MetricParserUtils.java) +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Component.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) +- [FlinkDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-core/src/main/java/io/datavines/engine/flink/core/FlinkDataVinesBootstrap.java) +- [SparkDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-core/src/main/java/io/datavines/engine/spark/core/SparkDataVinesBootstrap.java) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +DataVines引擎是数据质量验证系统的核心执行组件,负责解析作业配置、初始化执行环境并协调数据源、转换和接收器组件的执行。本文档详细阐述了`BaseDataVinesBootstrap`作为所有执行引擎基类的生命周期管理机制,`ConfigParser`的配置解析流程,以及`ParserUtils`和`QuoteIdentifier`在SQL语义处理中的作用。 + +## 项目结构 +DataVines引擎模块采用插件化架构,核心组件与具体执行引擎实现分离。主要模块包括: +- `datavines-engine-api`: 定义核心接口 +- `datavines-engine-core`: 封装通用执行流程 +- `datavines-engine-config`: 负责配置转换 +- `datavines-engine-common`: 提供通用工具类 +- `datavines-engine-plugins`: 包含不同执行引擎的具体实现 + +```mermaid +graph TD +subgraph "核心模块" +API[datavines-engine-api] +Core[datavines-engine-core] +Config[datavines-engine-config] +Common[datavines-engine-common] +end +subgraph "插件模块" +Local[datavines-engine-local] +Flink[datavines-engine-flink] +Spark[datavines-engine-spark] +end +API --> Core +Config --> Core +Common --> Core +Core --> Local +Core --> Flink +Core --> Spark +``` + +**图源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +**节源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +## 核心组件 +`BaseDataVinesBootstrap`是所有执行引擎的基类,负责管理引擎的初始化、配置解析和生命周期。`ConfigParser`负责将JSON配置文件解析为可执行的组件实例。`ParserUtils`和`QuoteIdentifier`提供字符串编码和SQL标识符处理的通用功能。 + +**节源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) +- [ParserUtils.java](file://datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/ParserUtils.java) +- [QuoteIdentifier.java](file://datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/QuoteIdentifier.java) + +## 架构概述 +DataVines引擎采用分层架构,从配置解析到执行的完整流程如下: + +```mermaid +sequenceDiagram +participant Bootstrap as BaseDataVinesBootstrap +participant ConfigParser as ConfigParser +participant RuntimeEnv as RuntimeEnvironment +participant Execution as Execution +participant Component as Component +Bootstrap->>Bootstrap : execute(args) +Bootstrap->>ConfigParser : new ConfigParser(configFile) +ConfigParser->>ConfigParser : load() 解析JSON配置 +ConfigParser->>ConfigParser : createRuntimeEnvironment() +ConfigParser->>Bootstrap : 返回解析后的组件列表 +Bootstrap->>Bootstrap : checkConfig() 验证组件配置 +Bootstrap->>Bootstrap : prepare() 准备运行环境 +Bootstrap->>Execution : 执行组件 +loop 每个组件 +Execution->>Component : 执行 +end +Bootstrap->>Bootstrap : stop() 清理资源 +``` + +**图源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +## 详细组件分析 + +### BaseDataVinesBootstrap 分析 +`BaseDataVinesBootstrap`作为抽象基类,定义了所有执行引擎的通用执行流程和生命周期管理。 + +#### 生命周期管理 +```mermaid +stateDiagram-v2 +[*] --> 初始化 +初始化 --> 配置解析 : parseConfigAndExecute +配置解析 --> 配置验证 : checkConfig +配置验证 --> 环境准备 : prepare +环境准备 --> 执行 : execution.execute +执行 --> 资源清理 : finally stop() +资源清理 --> [*] +配置验证 --> 异常处理 : throw Exception +执行 --> 异常处理 : catch Exception +异常处理 --> 资源清理 +``` + +**图源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +#### 初始化流程 +`BaseDataVinesBootstrap`的初始化流程包括配置解析、组件验证和环境准备三个主要阶段。首先通过`ConfigParser`加载配置文件,然后验证所有组件的配置有效性,最后准备运行环境并启动执行。 + +**节源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +### ConfigParser 分析 +`ConfigParser`负责将JSON格式的作业配置解析为可执行的组件实例。 + +#### 配置解析流程 +```mermaid +flowchart TD +Start([开始]) --> LoadConfig["加载配置文件"] +LoadConfig --> ParseJSON["解析JSON为DataVinesJobConfig"] +ParseJSON --> CreateEnv["创建RuntimeEnvironment"] +CreateEnv --> GetSources["获取Source组件"] +GetSources --> GetTransforms["获取Transform组件"] +GetTransforms --> GetSinks["获取Sink组件"] +GetSinks --> ReturnComponents["返回组件列表"] +ReturnComponents --> End([结束]) +``` + +**图源** +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +#### 配置转换机制 +`ConfigParser`使用SPI机制动态加载不同类型的组件。通过`PluginLoader`根据配置中的引擎类型、组件类型等信息创建相应的组件实例,并将配置参数注入到组件中。 + +**节源** +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +### ParserUtils 和 QuoteIdentifier 分析 +这两个工具类提供字符串处理和SQL标识符引用的通用功能。 + +#### ParserUtils 作用 +`ParserUtils`提供URL编码和解码功能,用于安全地处理包含特殊字符的字符串。 + +```mermaid +classDiagram +class ParserUtils { ++static String encode(String str) ++static String decode(String str) +-ParserUtils() +} +``` + +**图源** +- [ParserUtils.java](file://datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/ParserUtils.java) + +#### QuoteIdentifier 作用 +`QuoteIdentifier`提供SQL标识符引用功能,确保标识符在SQL语句中的正确性。 + +```mermaid +classDiagram +class QuoteIdentifier { ++static String quote(String entity) ++static String quote(String entity, boolean force) +} +``` + +**图源** +- [QuoteIdentifier.java](file://datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/QuoteIdentifier.java) + +**节源** +- [ParserUtils.java](file://datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/ParserUtils.java) +- [QuoteIdentifier.java](file://datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/QuoteIdentifier.java) + +## 依赖分析 +DataVines引擎各组件之间的依赖关系清晰,采用接口隔离和依赖注入模式。 + +```mermaid +erDiagram +BaseDataVinesBootstrap ||--o{ ConfigParser : "使用" +ConfigParser ||--o{ DataVinesJobConfig : "解析" +ConfigParser ||--o{ RuntimeEnvironment : "创建" +ConfigParser ||--o{ Component : "生成" +BaseDataVinesBootstrap ||--o{ Execution : "执行" +Component ||--o{ RuntimeEnvironment : "准备" +``` + +**图源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +**节源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +## 性能考虑 +引擎设计考虑了性能优化,包括: +- 配置解析的懒加载机制 +- 组件实例的复用 +- 异常处理的快速失败模式 +- 资源的及时清理 + +## 故障排除指南 +常见问题及解决方案: +- 配置文件路径错误:确保配置文件路径正确且可读 +- 组件配置无效:检查组件配置参数是否符合要求 +- 运行环境创建失败:确认引擎类型和配置正确 +- 执行异常:查看日志定位具体错误 + +**节源** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +## 结论 +DataVines核心引擎采用模块化和插件化设计,通过`BaseDataVinesBootstrap`统一管理执行流程,`ConfigParser`实现配置解析,以及各种工具类提供辅助功能,形成了一个灵活、可扩展的数据质量验证执行框架。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/datavines-metric\346\250\241\345\235\227.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/datavines-metric\346\250\241\345\235\227.md" new file mode 100644 index 00000000..70d26ac8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/datavines-metric\346\250\241\345\235\227.md" @@ -0,0 +1,1793 @@ +# datavines-metric模块 + + +**本文档引用的文件** +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [MetricExecutionResult.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricExecutionResult.java) +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java) +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) +- [FixValue.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-fix/src/main/java/io/datavines/metric/expected/plugin/FixValue.java) +- [DailyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) +- [TableTotalRows.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-table-rows/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java) +- [TargetTableTotalRows.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-target-table-rows/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java) +- [None.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-none/src/main/java/io/datavines/metric/expected/plugin/None.java) +- [Count.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-count/src/main/java/io/datavines/metric/result/formula/Count.java) +- [Diff.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff/src/main/java/io/datavines/metric/result/formula/Diff.java) +- [DiffPercentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-percentage/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java) +- [Percentage.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-percentage/src/main/java/io/datavines/metric/result/formula/Percentage.java) +- [ActualMinusExpectedDiff.java](file://datavines-metric/datavines-metric-result-formula-plugins/datavines-metric-result-formula-diff-actual-expected/src/main/java/io/datavines/metric/result/formula/ActualMinusExpectedDiff.java) + + +## 目录 +1. [引言](#引言) +2. [核心功能概述](#核心功能概述) +3. [内置检查规则](#内置检查规则) +4. [预期值计算策略](#预期值计算策略) +5. [结果验证机制](#结果验证机制) +6. [度量配置体系](#度量配置体系) +7. [单表列检查实现原理](#单表列检查实现原理) +8. [跨表准确性检查实现原理](#跨表准确性检查实现原理) +9. [自定义SQL检查实现原理](#自定义sql检查实现原理) +10. [自定义度量规则开发指南](#自定义度量规则开发指南) +11. [性能优化策略](#性能优化策略) +12. [复杂场景使用示例](#复杂场景使用示例) +13. [结论](#结论) + +## 引言 + +datavines-metric模块是DataVines数据质量框架的核心组件,负责实现数据质量度量的完整生命周期管理。该模块提供了一套完整的数据质量检查体系,包括27种内置检查规则、灵活的预期值计算策略、精确的结果验证机制和可扩展的度量配置功能。通过标准化的接口设计和插件化架构,该模块能够支持单表列检查、跨表准确性检查和自定义SQL检查等多种数据质量验证场景,为大数据环境下的数据质量管理提供了强大的技术支持。 + +**本节来源** +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) + +## 核心功能概述 + +datavines-metric模块作为数据质量度量的核心引擎,提供了全面的数据质量验证功能。模块采用插件化架构设计,通过定义标准化的接口和抽象基类,实现了高度的可扩展性和灵活性。核心功能包括数据质量检查规则的定义与执行、预期值的计算与比较、检查结果的验证与评分,以及度量配置的管理与解析。 + +模块通过`SqlMetric`接口定义了度量规则的基本行为,包括获取检查名称、维度、类型、实际值SQL、无效项SQL等。`ExpectedValue`接口则负责预期值的计算策略,支持固定值、历史平均值、目标表行数等多种计算方式。`ResultFormula`接口定义了实际值与预期值的比较公式,如差值、百分比、差异百分比等。`MetricValidator`类提供了结果验证的统一逻辑,通过比较操作符和阈值判断检查结果是否通过。 + +```mermaid +graph TD +A[度量配置] --> B[度量规则] +B --> C[实际值计算] +B --> D[预期值计算] +C --> E[结果比较] +D --> E +E --> F[结果验证] +F --> G[质量评分] +H[检查规则] --> B +I[预期值策略] --> D +J[结果公式] --> E +``` + +**图表来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) + +**本节来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) + +## 内置检查规则 + +datavines-metric模块提供了27种内置的数据质量检查规则,覆盖了数据完整性、准确性、一致性、唯一性等多个维度。这些规则按照功能可分为单表列检查、单表行检查、跨表检查和自定义SQL检查四大类。 + +### 单表列检查规则 + +单表列检查规则主要针对表中特定列的数据质量进行验证,包括: + +- **空值检查** (`column_null`):检查指定列中是否存在空值 +- **非空检查** (`column_not_null`):检查指定列中是否存在非空值 +- **枚举值检查** (`column_in_enums`):检查指定列的值是否在预定义的枚举值范围内 +- **非枚举值检查** (`column_not_in_enums`):检查指定列的值是否不在预定义的枚举值范围内 +- **正则匹配检查** (`column_match_regex`):检查指定列的值是否符合指定的正则表达式模式 +- **正则不匹配检查** (`column_match_not_regex`):检查指定列的值是否不符合指定的正则表达式模式 +- **值范围检查** (`column_value_between`):检查指定列的值是否在指定的数值范围内 +- **长度检查** (`column_length`):检查指定列的值长度是否符合要求 +- **最小长度检查** (`column_min_length`):检查指定列的值长度是否大于等于最小长度 +- **最大长度检查** (`column_max_length`):检查指定列的值长度是否小于等于最大长度 +- **平均长度检查** (`column_avg_length`):检查指定列的值平均长度是否符合要求 + +### 单表数值检查规则 + +单表数值检查规则主要针对数值型列的统计特征进行验证: + +- **最小值检查** (`column_min`):检查指定列的最小值是否符合要求 +- **最大值检查** (`column_max`):检查指定列的最大值是否符合要求 +- **平均值检查** (`column_avg`):检查指定列的平均值是否符合要求 +- **总和检查** (`column_sum`):检查指定列的总和是否符合要求 +- **标准差检查** (`column_std_dev`):检查指定列的标准差是否符合要求 +- **方差检查** (`column_variance`):检查指定列的方差是否符合要求 +- **唯一值检查** (`column_unique`):检查指定列的唯一值数量是否符合要求 +- **重复值检查** (`column_duplicate`):检查指定列的重复值数量是否符合要求 +- **不同值检查** (`column_distinct`):检查指定列的不同值数量是否符合要求 + +### 表级检查规则 + +表级检查规则主要针对整个表的数据质量进行验证: + +- **表行数检查** (`table_row_count`):检查表的行数是否符合要求 +- **表新鲜度检查** (`table_freshness`):检查表的数据新鲜度是否符合要求 + +### 跨表检查规则 + +跨表检查规则主要针对多个表之间的数据一致性进行验证: + +- **跨表准确性检查** (`multi_table_accuracy`):检查源表和目标表之间的数据准确性 +- **跨表值比较检查** (`multi_table_value_comparison`):比较两个表之间的特定字段值 + +### 自定义检查规则 + +自定义检查规则提供了灵活的SQL自定义能力: + +- **自定义聚合SQL检查** (`custom_aggregate_sql`):允许用户自定义聚合SQL进行数据质量检查 + +```mermaid +graph TD +A[检查规则] --> B[单表列检查] +A --> C[单表数值检查] +A --> D[表级检查] +A --> E[跨表检查] +A --> F[自定义检查] +B --> B1[空值检查] +B --> B2[非空检查] +B --> B3[枚举值检查] +B --> B4[非枚举值检查] +B --> B5[正则匹配检查] +B --> B6[正则不匹配检查] +B --> B7[值范围检查] +B --> B8[长度检查] +B --> B9[最小长度检查] +B --> B10[最大长度检查] +B --> B11[平均长度检查] +C --> C1[最小值检查] +C --> C2[最大值检查] +C --> C3[平均值检查] +C --> C4[总和检查] +C --> C5[标准差检查] +C --> C6[方差检查] +C --> C7[唯一值检查] +C --> C8[重复值检查] +C --> C9[不同值检查] +D --> D1[表行数检查] +D --> D2[表新鲜度检查] +E --> E1[跨表准确性检查] +E --> E2[跨表值比较检查] +F --> F1[自定义聚合SQL检查] +``` + +**图表来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) + +**本节来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) + +## 预期值计算策略 + +datavines-metric模块提供了多种预期值计算策略,通过`ExpectedValue`接口实现。这些策略允许用户根据不同的业务场景选择合适的预期值计算方法,确保数据质量检查的灵活性和准确性。 + +### 预期值策略接口 + +`ExpectedValue`接口定义了预期值计算的基本方法: + +- `getName()`:获取策略名称 +- `getZhName()`:获取策略中文名称 +- `getKey(Map inputParameter)`:获取策略键值 +- `getExecuteSql(Map inputParameter)`:获取执行SQL +- `getOutputTable(Map inputParameter)`:获取输出表名 +- `isNeedDefaultDatasource()`:判断是否需要默认数据源 +- `prepare(Map config)`:准备配置 + +### 固定值策略 + +固定值策略(`FixValue`)是最简单的预期值计算方式,用户直接指定一个固定的数值作为预期值。这种策略适用于已知确切目标值的场景,如每日订单量目标为10000单。 + +```java +public class FixValue implements ExpectedValue { + @Override + public String getName() { + return "fix"; + } + + @Override + public String getZhName() { + return "固定值"; + } + + @Override + public String getKey(Map inputParameter) { + return "fix_value"; + } + + @Override + public String getExecuteSql(Map inputParameter) { + return "SELECT " + inputParameter.get("fix_value") + " as expected_value"; + } + + @Override + public String getOutputTable(Map inputParameter) { + return "fix_value_table"; + } + + @Override + public boolean isNeedDefaultDatasource() { + return false; + } + + @Override + public void prepare(Map config) { + // 准备配置 + } +} +``` + +### 历史平均值策略 + +历史平均值策略通过计算历史数据的平均值来确定预期值,包括日平均值、周平均值、月平均值等。这些策略适用于数据波动较小、具有稳定趋势的场景。 + +#### 日平均值策略 + +日平均值策略(`DailyAvg`)计算过去N天的平均值作为预期值: + +```java +public class DailyAvg implements ExpectedValue { + @Override + public String getName() { + return "daily_avg"; + } + + @Override + public String getZhName() { + return "日平均值"; + } + + @Override + public String getExecuteSql(Map inputParameter) { + int days = Integer.parseInt(inputParameter.get("days")); + String dateColumn = inputParameter.get("date_column"); + String valueColumn = inputParameter.get("value_column"); + String table = inputParameter.get("table"); + + return String.format( + "SELECT AVG(%s) as expected_value FROM %s WHERE %s >= DATE_SUB(CURDATE(), INTERVAL %d DAY)", + valueColumn, table, dateColumn, days + ); + } +} +``` + +#### 7日平均值策略 + +7日平均值策略(`Last7DayAvg`)计算过去7天的平均值作为预期值: + +```java +public class Last7DayAvg implements ExpectedValue { + @Override + public String getName() { + return "last_7_day_avg"; + } + + @Override + public String getZhName() { + return "近7日平均值"; + } + + @Override + public String getExecuteSql(Map inputParameter) { + String dateColumn = inputParameter.get("date_column"); + String valueColumn = inputParameter.get("value_column"); + String table = inputParameter.get("table"); + + return String.format( + "SELECT AVG(%s) as expected_value FROM %s WHERE %s >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)", + valueColumn, table, dateColumn + ); + } +} +``` + +#### 30日平均值策略 + +30日平均值策略(`Last30DayAvg`)计算过去30天的平均值作为预期值: + +```java +public class Last30DayAvg implements ExpectedValue { + @Override + public String getName() { + return "last_30_day_avg"; + } + + @Override + public String getZhName() { + return "近30日平均值"; + } + + @Override + public String getExecuteSql(Map inputParameter) { + String dateColumn = inputParameter.get("date_column"); + String valueColumn = inputParameter.get("value_column"); + String table = inputParameter.get("table"); + + return String.format( + "SELECT AVG(%s) as expected_value FROM %s WHERE %s >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)", + valueColumn, table, dateColumn + ); + } +} +``` + +### 周期性平均值策略 + +周期性平均值策略根据特定周期计算平均值,包括周平均值、月平均值等。 + +#### 周平均值策略 + +周平均值策略(`WeeklyAvg`)计算上周的平均值作为预期值: + +```java +public class WeeklyAvg implements ExpectedValue { + @Override + public String getName() { + return "weekly_avg"; + } + + @Override + public String getZhName() { + return "周平均值"; + } + + @Override + public String getExecuteSql(Map inputParameter) { + String dateColumn = inputParameter.get("date_column"); + String valueColumn = inputParameter.get("value_column"); + String table = inputParameter.get("table"); + + return String.format( + "SELECT AVG(%s) as expected_value FROM %s WHERE YEARWEEK(%s) = YEARWEEK(CURDATE()) - 1", + valueColumn, table, dateColumn + ); + } +} +``` + +#### 月平均值策略 + +月平均值策略(`MonthlyAvg`)计算上月的平均值作为预期值: + +```java +public class MonthlyAvg implements ExpectedValue { + @Override + public String getName() { + return "monthly_avg"; + } + + @Override + public String getZhName() { + return "月平均值"; + } + + @Override + public String getExecuteSql(Map inputParameter) { + String dateColumn = inputParameter.get("date_column"); + String valueColumn = inputParameter.get("value_column"); + String table = inputParameter.get("table"); + + return String.format( + "SELECT AVG(%s) as expected_value FROM %s WHERE YEAR(%s) = YEAR(CURDATE()) AND MONTH(%s) = MONTH(CURDATE()) - 1", + valueColumn, table, dateColumn, dateColumn + ); + } +} +``` + +### 表行数策略 + +表行数策略通过查询表的实际行数作为预期值,包括当前表行数和目标表行数。 + +#### 当前表行数策略 + +当前表行数策略(`TableTotalRows`)查询指定表的总行数作为预期值: + +```java +public class TableTotalRows implements ExpectedValue { + @Override + public String getName() { + return "table_rows"; + } + + @Override + public String getZhName() { + return "表行数"; + } + + @Override + public String getExecuteSql(Map inputParameter) { + String table = inputParameter.get("table"); + return String.format("SELECT COUNT(*) as expected_value FROM %s", table); + } +} +``` + +#### 目标表行数策略 + +目标表行数策略(`TargetTableTotalRows`)查询目标表的总行数作为预期值,常用于数据同步场景: + +```java +public class TargetTableTotalRows implements ExpectedValue { + @Override + public String getName() { + return "target_table_rows"; + } + + @Override + public String getZhName() { + return "目标表行数"; + } + + @Override + public String getExecuteSql(Map inputParameter) { + String targetTable = inputParameter.get("target_table"); + return String.format("SELECT COUNT(*) as expected_value FROM %s", targetTable); + } +} +``` + +### 无预期值策略 + +无预期值策略(`None`)表示不使用预期值,通常用于仅需要计算实际值的场景: + +```java +public class None implements ExpectedValue { + @Override + public String getName() { + return "none"; + } + + @Override + public String getZhName() { + return "无"; + } + + @Override + public String getExecuteSql(Map inputParameter) { + return "SELECT 0 as expected_value"; + } + + @Override + public boolean isNeedDefaultDatasource() { + return false; + } +} +``` + +```mermaid +classDiagram +class ExpectedValue { +<> ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class FixValue { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class DailyAvg { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class Last7DayAvg { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class Last30DayAvg { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class WeeklyAvg { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class MonthlyAvg { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class TableTotalRows { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class TargetTableTotalRows { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class None { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +ExpectedValue <|-- FixValue +ExpectedValue <|-- DailyAvg +ExpectedValue <|-- Last7DayAvg +ExpectedValue <|-- Last30DayAvg +ExpectedValue <|-- WeeklyAvg +ExpectedValue <|-- MonthlyAvg +ExpectedValue <|-- TableTotalRows +ExpectedValue <|-- TargetTableTotalRows +ExpectedValue <|-- None +``` + +**图表来源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [FixValue.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-fix/src/main/java/io/datavines/metric/expected/plugin/FixValue.java) +- [DailyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) +- [TableTotalRows.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-table-rows/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java) +- [TargetTableTotalRows.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-target-table-rows/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java) +- [None.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-none/src/main/java/io/datavines/metric/expected/plugin/None.java) + +**本节来源** +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [FixValue.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-fix/src/main/java/io/datavines/metric/expected/plugin/FixValue.java) +- [DailyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) +- [TableTotalRows.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-table-rows/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java) +- [TargetTableTotalRows.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-target-table-rows/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java) +- [None.java](file://datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-none/src/main/java/io/datavines/metric/expected/plugin/None.java) + +## 结果验证机制 + +datavines-metric模块通过`MetricValidator`类实现了统一的结果验证机制。该机制负责判断数据质量检查任务的结果是否通过,以及计算数据质量评分。 + +### 结果验证流程 + +结果验证流程主要包括以下几个步骤: + +1. 获取实际值和预期值 +2. 解析比较操作符 +3. 应用结果计算公式 +4. 比较结果与阈值 +5. 判断检查是否通过 +6. 计算质量评分 + +### 结果验证实现 + +`MetricValidator`类的核心方法是`isSuccess`和`getQualityScore`: + +```java +public class MetricValidator { + /** + * 判断数据质量任务结果是否通过 + */ + public static boolean isSuccess(MetricExecutionResult executionResult) { + BigDecimal actualValue = executionResult.getActualValue(); + BigDecimal expectedValue = executionResult.getExpectedValue(); + + OperatorType operatorType = OperatorType.of(StringUtils.trim(executionResult.getOperator())); + ResultFormula resultFormula = PluginLoader.getPluginLoader(ResultFormula.class) + .getOrCreatePlugin(executionResult.getResultFormula()); + + return getCompareResult(operatorType, + resultFormula.getResult(actualValue, expectedValue), + executionResult.getThreshold()); + } + + /** + * 计算数据质量评分 + */ + public static BigDecimal getQualityScore(MetricExecutionResult executionResult, boolean isSuccess) { + BigDecimal actualValue = executionResult.getActualValue(); + BigDecimal expectedValue = executionResult.getExpectedValue(); + + ResultFormula resultFormula = PluginLoader.getPluginLoader(ResultFormula.class) + .getOrCreatePlugin(executionResult.getResultFormula()); + SqlMetric metric = PluginLoader.getPluginLoader(SqlMetric.class) + .getOrCreatePlugin(executionResult.getMetricName()); + + return resultFormula.getScore(actualValue, expectedValue, isSuccess, metric.getDirectionType()); + } + + /** + * 比较结果与阈值 + */ + private static boolean getCompareResult(OperatorType operatorType, BigDecimal srcValue, BigDecimal targetValue) { + if (srcValue == null || targetValue == null) { + return false; + } + + switch (operatorType) { + case EQ: + return srcValue.compareTo(targetValue) == 0; + case LT: + return srcValue.compareTo(targetValue) <= -1; + case LTE: + return srcValue.compareTo(targetValue) == 0 || srcValue.compareTo(targetValue) <= -1; + case GT: + return srcValue.compareTo(targetValue) >= 1; + case GTE: + return srcValue.compareTo(targetValue) == 0 || srcValue.compareTo(targetValue) >= 1; + case NE: + return srcValue.compareTo(targetValue) != 0; + default: + return true; + } + } +} +``` + +### 比较操作符 + +模块支持以下比较操作符: + +- **等于** (`EQ`):实际值等于预期值 +- **小于** (`LT`):实际值小于预期值 +- **小于等于** (`LTE`):实际值小于等于预期值 +- **大于** (`GT`):实际值大于预期值 +- **大于等于** (`GTE`):实际值大于等于预期值 +- **不等于** (`NE`):实际值不等于预期值 + +### 结果计算公式 + +结果计算公式通过`ResultFormula`接口实现,支持多种计算方式: + +- **计数** (`count`):直接使用实际值 +- **差值** (`diff`):计算实际值与预期值的差值 +- **差异百分比** (`diff_percentage`):计算实际值与预期值的差异百分比 +- **百分比** (`percentage`):计算实际值占预期值的百分比 +- **实际值减预期值差值** (`actual_minus_expected_diff`):计算实际值减去预期值的差值 + +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant 度量执行 as 度量执行 +participant 验证器 as 结果验证器 +participant 公式 as 结果公式 +用户->>度量执行 : 执行度量检查 +度量执行->>度量执行 : 计算实际值 +度量执行->>度量执行 : 计算预期值 +度量执行->>验证器 : 调用isSuccess +验证器->>公式 : 获取结果公式 +公式-->>验证器 : 返回计算结果 +验证器->>验证器 : 比较结果与阈值 +验证器-->>度量执行 : 返回验证结果 +度量执行->>用户 : 返回检查结果 +``` + +**图表来源** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) + +**本节来源** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) + +## 度量配置体系 + +datavines-metric模块通过`ConfigItem`类和相关配置机制实现了灵活的度量配置体系。该体系允许用户为不同的度量规则配置必要的参数,确保检查的准确性和可定制性。 + +### 配置项定义 + +`ConfigItem`类定义了配置项的基本属性: + +- `key`:配置项的键名 +- `name`:配置项的显示名称 +- `description`:配置项的描述 +- `defaultValue`:配置项的默认值 +- `required`:是否为必填项 + +### 配置管理 + +度量规则通过`getConfigMap`方法返回配置项映射,定义了该规则所需的全部配置参数。例如,`TableRowCount`规则的配置管理: + +```java +@Override +public Map getConfigMap() { + configMap.put("table",new ConfigItem("table", "表名", "table", true)); + return configMap; +} +``` + +### 配置验证 + +模块通过`ConfigChecker`类实现了配置验证功能,确保用户提供的配置参数符合要求: + +```java +@Override +public CheckResult validateConfig(Map config) { + return ConfigChecker.checkConfig(config, requiredOptions); +} +``` + +### 配置准备 + +`prepare`方法用于在执行度量检查前准备和处理配置参数: + +```java +@Override +public void prepare(Map config) { + // 如果过滤条件不为空,则添加到过滤器列表 + if (config.containsKey("filter") && StringUtils.isNotBlank(config.get("filter"))) { + filters.add(config.get("filter")); + } + + addFiltersIntoInvalidateItemsSql(); +} +``` + +### 配置示例 + +以下是几种典型度量规则的配置示例: + +#### 表行数检查配置 + +```json +{ + "table": "orders", + "filter": "order_date >= '2023-01-01'" +} +``` + +#### 空值检查配置 + +```json +{ + "table": "users", + "column": "email", + "filter": "status = 'active'" +} +``` + +#### 跨表准确性检查配置 + +```json +{ + "table": "source_orders", + "table2": "target_orders", + "filter": "order_date >= '2023-01-01'", + "filter2": "order_date >= '2023-01-01'", + "on_clause": "source_orders.order_id = target_orders.order_id", + "where_clause": "source_orders.amount != target_orders.amount" +} +``` + +#### 自定义聚合SQL检查配置 + +```json +{ + "table": "sales", + "actual_aggregate_sql": "SELECT SUM(amount) as actual_value FROM sales WHERE sale_date >= '2023-01-01'" +} +``` + +```mermaid +classDiagram +class ConfigItem { ++String key ++String name ++String description ++String defaultValue ++boolean required ++ConfigItem(String key, String name, String description) ++ConfigItem(String key, String name, String description, boolean required) +} +class SqlMetric { +<> ++Map getConfigMap() ++CheckResult validateConfig(Map config) ++void prepare(Map config) +} +class ConfigChecker { ++static CheckResult checkConfig(Map config, Set requiredOptions) +} +class CheckResult { ++boolean isSuccess ++String msg ++CheckResult(boolean isSuccess, String msg) +} +SqlMetric <|-- TableRowCount +SqlMetric <|-- ColumnNull +SqlMetric <|-- MultiTableAccuracy +SqlMetric <|-- CustomAggregateSql +``` + +**图表来源** +- [ConfigItem.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ConfigItem.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ConfigChecker.java](file://datavines-common/src/main/java/io/datavines/common/config/ConfigChecker.java) +- [CheckResult.java](file://datavines-common/src/main/java/io/datavines/common/config/CheckResult.java) +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) + +**本节来源** +- [ConfigItem.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ConfigItem.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ConfigChecker.java](file://datavines-common/src/main/java/io/datavines/common/config/ConfigChecker.java) +- [CheckResult.java](file://datavines-common/src/main/java/io/datavines/common/config/CheckResult.java) +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) + +## 单表列检查实现原理 + +单表列检查是datavines-metric模块中最基础的检查类型,主要针对单个表中特定列的数据质量进行验证。该检查类型通过继承`BaseSingleTableColumnNotUseView`基类实现,提供了统一的实现框架。 + +### 基类设计 + +`BaseSingleTableColumnNotUseView`类继承自`BaseSingleTable`,为单表列检查提供了基础功能: + +```java +public abstract class BaseSingleTableColumnNotUseView extends BaseSingleTable { + protected StringBuilder invalidateItemsSql = new StringBuilder("select * from ${table}"); + + protected List filters = new ArrayList<>(); + + protected HashMap configMap = new HashMap<>(); + + protected Set requiredOptions = new HashSet<>(); + + public BaseSingleTableColumnNotUseView() { + super(); + configMap.put("column",new ConfigItem("column", "列名", "column")); + requiredOptions.add("column"); + } + + @Override + public void prepare(Map config) { + super.prepare(config); + } +} +``` + +### 空值检查实现 + +以`ColumnNull`为例,展示单表列检查的具体实现: + +```java +public class ColumnNull extends BaseSingleTableColumnNotUseView { + public ColumnNull(){ + super(); + } + + @Override + public String getName() { + return "column_null"; + } + + @Override + public String getZhName() { + return "空值检查"; + } + + @Override + public MetricDimension getDimension() { + return MetricDimension.COMPLETENESS; + } + + @Override + public MetricType getType() { + return MetricType.SINGLE_TABLE; + } + + @Override + public boolean isInvalidateItemsCanOutput() { + return true; + } + + @Override + public void prepare(Map config) { + if (config.containsKey("column")) { + filters.add(getConnectorFactory(config).getMetricScript().columnIsNull()); + } + super.prepare(config); + } + + @Override + public List suitableType() { + return Arrays.asList(DataVinesDataType.NUMERIC_TYPE, DataVinesDataType.STRING_TYPE, DataVinesDataType.DATE_TIME_TYPE); + } + + @Override + public MetricDirectionType getDirectionType() { + return MetricDirectionType.NEGATIVE; + } +} +``` + +### 实现原理分析 + +单表列检查的实现原理主要包括以下几个方面: + +1. **SQL生成**:通过模板化SQL语句,动态生成实际执行的SQL +2. **过滤条件**:支持用户自定义过滤条件,提高检查的灵活性 +3. **连接器适配**:通过`ConnectorFactory`适配不同数据源的SQL语法差异 +4. **结果处理**:统一处理检查结果,确保结果格式的一致性 + +### 执行流程 + +单表列检查的执行流程如下: + +1. 用户配置检查参数(表名、列名、过滤条件等) +2. 系统验证配置参数的合法性 +3. 准备SQL执行环境 +4. 生成无效项查询SQL +5. 执行无效项查询,获取不符合条件的数据 +6. 生成实际值查询SQL +7. 执行实际值查询,获取检查结果 +8. 计算预期值 +9. 验证检查结果 +10. 返回最终检查报告 + +```mermaid +flowchart TD +A[开始] --> B[配置检查参数] +B --> C[验证配置] +C --> D{配置有效?} +D --> |否| E[返回错误] +D --> |是| F[准备执行环境] +F --> G[生成无效项SQL] +G --> H[执行无效项查询] +H --> I[生成实际值SQL] +I --> J[执行实际值查询] +J --> K[计算预期值] +K --> L[验证结果] +L --> M[生成报告] +M --> N[结束] +``` + +**图表来源** +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumnNotUseView.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) + +**本节来源** +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumnNotUseView.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) + +## 跨表准确性检查实现原理 + +跨表准确性检查是datavines-metric模块中用于验证多个表之间数据一致性的高级检查类型。该检查类型通过`MultiTableAccuracy`类实现,支持源表和目标表之间的数据对比。 + +### 接口定义 + +`MultiTableAccuracy`类实现了`SqlMetric`接口,定义了跨表准确性检查的基本行为: + +```java +public class MultiTableAccuracy implements SqlMetric { + private final StringBuilder sourceTableSql = new StringBuilder("SELECT * FROM ${table}"); + private final StringBuilder targetTableSql = new StringBuilder("SELECT * FROM ${table2}"); + private final StringBuilder invalidateItemsSql = new StringBuilder("SELECT ${table_alias_columns}, ${table2_alias_columns} FROM "); + + @Override + public String getName() { + return "multi_table_accuracy"; + } + + @Override + public String getZhName() { + return "跨表准确性检查"; + } + + @Override + public MetricDimension getDimension() { + return MetricDimension.ACCURACY; + } + + @Override + public MetricType getType() { + return MetricType.MULTI_TABLE_ACCURACY; + } + + @Override + public boolean isInvalidateItemsCanOutput() { + return true; + } +} +``` + +### SQL生成机制 + +跨表准确性检查的核心是动态SQL生成机制,通过模板化方式构建复杂的JOIN查询: + +```java +@Override +public void prepare(Map config) { + if (config.containsKey("filter") && StringUtils.isNotBlank(config.get("filter"))) { + sourceTableSql.append(" WHERE (${filter}) "); + } + + if (config.containsKey("filter2") && StringUtils.isNotBlank(config.get("filter2"))) { + targetTableSql.append(" WHERE (${filter2}) "); + } + + invalidateItemsSql + .append("(").append(sourceTableSql).append(")").append(" ${table_alias} ") + .append(" LEFT JOIN ") + .append("(").append(targetTableSql).append(")").append(" ${table2_alias} ") + .append("ON ${on_clause} WHERE ${where_clause}"); +} +``` + +### 执行流程 + +跨表准确性检查的执行流程如下: + +1. 用户配置源表和目标表信息 +2. 配置JOIN条件和过滤条件 +3. 生成源表查询SQL +4. 生成目标表查询SQL +5. 构建JOIN查询SQL +6. 执行JOIN查询,获取不匹配的数据 +7. 统计不匹配数据的数量 +8. 计算预期值 +9. 验证检查结果 +10. 返回最终检查报告 + +### 配置参数 + +跨表准确性检查支持以下配置参数: + +- `table`:源表名 +- `table2`:目标表名 +- `filter`:源表过滤条件 +- `filter2`:目标表过滤条件 +- `on_clause`:JOIN条件 +- `where_clause`:结果过滤条件 +- `table_alias`:源表别名 +- `table2_alias`:目标表别名 + +### 实际应用示例 + +假设需要检查订单表和发货表之间的数据一致性: + +```json +{ + "table": "orders", + "table2": "shipments", + "filter": "order_date >= '2023-01-01'", + "filter2": "shipment_date >= '2023-01-01'", + "on_clause": "orders.order_id = shipments.order_id", + "where_clause": "orders.amount != shipments.amount OR orders.customer_id != shipments.customer_id" +} +``` + +该配置将检查2023年1月1日之后的订单和发货记录,找出金额或客户ID不匹配的记录。 + +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant 检查器 as 跨表准确性检查器 +participant SQL生成 as SQL生成器 +participant 执行引擎 as 执行引擎 +用户->>检查器 : 配置检查参数 +检查器->>SQL生成 : 调用prepare方法 +SQL生成->>SQL生成 : 生成源表SQL +SQL生成->>SQL生成 : 生成目标表SQL +SQL生成->>SQL生成 : 构建JOIN查询 +SQL生成-->>检查器 : 返回生成的SQL +检查器->>执行引擎 : 执行无效项查询 +执行引擎-->>检查器 : 返回不匹配数据 +检查器->>执行引擎 : 执行实际值查询 +执行引擎-->>检查器 : 返回统计结果 +检查器->>用户 : 返回检查报告 +``` + +**图表来源** +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) + +**本节来源** +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) + +## 自定义SQL检查实现原理 + +自定义SQL检查是datavines-metric模块中提供最高灵活性的检查类型,允许用户通过自定义SQL语句实现复杂的质量检查逻辑。该检查类型通过`CustomAggregateSql`类实现。 + +### 接口实现 + +`CustomAggregateSql`类实现了`SqlMetric`接口,提供了自定义SQL检查的核心功能: + +```java +public class CustomAggregateSql implements SqlMetric { + private final Set requiredOptions = new HashSet<>(); + private final HashMap configMap = new HashMap<>(); + + public CustomAggregateSql() { + configMap.put("actual_aggregate_sql", new ConfigItem("actual_aggregate_sql","自定义聚合SQL","actual_aggregate_sql")); + requiredOptions.add("actual_aggregate_sql"); + } + + @Override + public String getName() { + return "custom_aggregate_sql"; + } + + @Override + public String getZhName() { + return "自定义聚合SQL"; + } + + @Override + public MetricDimension getDimension() { + return MetricDimension.ACCURACY; + } + + @Override + public MetricType getType() { + return MetricType.SINGLE_TABLE; + } + + @Override + public boolean isInvalidateItemsCanOutput() { + return false; + } + + @Override + public CheckResult validateConfig(Map config) { + return ConfigChecker.checkConfig(config, requiredOptions); + } + + @Override + public Map getConfigMap() { + return configMap; + } +} +``` + +### SQL处理机制 + +自定义SQL检查的核心是SQL处理机制,能够正确处理用户提供的自定义SQL语句: + +```java +@Override +public ExecuteSql getActualValue(Map inputParameter) { + inputParameter.put(ACTUAL_TABLE, inputParameter.get(TABLE)); + String actualAggregateSql = inputParameter.get(ACTUAL_AGGREGATE_SQL); + if (StringUtils.isNotEmpty(actualAggregateSql)) { + if (actualAggregateSql.contains("as actual_value")) { + actualAggregateSql = actualAggregateSql.replace("as actual_value", "as actual_value_" + inputParameter.get(METRIC_UNIQUE_KEY)); + } else if (actualAggregateSql.contains("AS actual_value")) { + actualAggregateSql = actualAggregateSql.replace("AS actual_value", "as actual_value_" + inputParameter.get(METRIC_UNIQUE_KEY)); + } + } + return new ExecuteSql(actualAggregateSql, inputParameter.get(TABLE)); +} +``` + +### 实现特点 + +自定义SQL检查具有以下特点: + +1. **高度灵活**:用户可以编写任意复杂的SQL语句 +2. **参数化支持**:支持模板变量替换,如`${table}`、`${column}`等 +3. **结果标准化**:自动处理结果列名,确保与系统兼容 +4. **安全性考虑**:对SQL语句进行基本的安全检查 + +### 使用场景 + +自定义SQL检查适用于以下场景: + +- 复杂的业务逻辑验证 +- 多表关联查询检查 +- 特殊的数据质量规则 +- 临时性的数据探查 + +### 配置示例 + +```json +{ + "table": "sales", + "actual_aggregate_sql": "SELECT SUM(amount) as actual_value FROM sales WHERE sale_date >= '2023-01-01' AND region = 'North'" +} +``` + +该配置将计算2023年1月1日之后北方地区的销售总额。 + +```mermaid +flowchart TD +A[开始] --> B[配置自定义SQL] +B --> C[验证SQL语法] +C --> D{SQL有效?} +D --> |否| E[返回错误] +D --> |是| F[替换模板变量] +F --> G[执行自定义SQL] +G --> H{执行成功?} +H --> |否| I[返回执行错误] +H --> |是| J[处理查询结果] +J --> K[标准化结果格式] +K --> L[返回检查结果] +L --> M[结束] +``` + +**图表来源** +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) + +## 自定义度量规则开发指南 + +datavines-metric模块提供了强大的扩展能力,允许开发者创建自定义的度量规则。本指南将详细介绍如何开发和注册自定义度量规则。 + +### 开发环境准备 + +在开始开发自定义度量规则之前,需要准备以下环境: + +1. JDK 8或更高版本 +2. Maven 3.6或更高版本 +3. IDE(如IntelliJ IDEA或Eclipse) +4. datavines-metric模块源码 + +### 创建自定义规则类 + +自定义度量规则需要实现`SqlMetric`接口或继承现有的基类。以下是一个自定义规则的示例: + +```java +package io.datavines.metric.plugin; + +import io.datavines.common.entity.ExecuteSql; +import io.datavines.common.enums.DataVinesDataType; +import io.datavines.metric.api.*; +import io.datavines.metric.plugin.base.BaseSingleTable; + +import java.util.*; + +public class CustomDataQualityRule extends BaseSingleTable { + public CustomDataQualityRule() { + super(); + // 添加自定义配置项 + configMap.put("threshold", new ConfigItem("threshold", "阈值", "threshold", true)); + configMap.put("pattern", new ConfigItem("pattern", "匹配模式", "pattern")); + + requiredOptions.add("threshold"); + } + + @Override + public String getName() { + return "custom_data_quality_rule"; + } + + @Override + public String getZhName() { + return "自定义数据质量规则"; + } + + @Override + public MetricDimension getDimension() { + return MetricDimension.CONSISTENCY; + } + + @Override + public MetricType getType() { + return MetricType.SINGLE_TABLE; + } + + @Override + public boolean isInvalidateItemsCanOutput() { + return true; + } + + @Override + public void prepare(Map config) { + super.prepare(config); + + // 根据配置准备SQL + String pattern = config.get("pattern"); + if (pattern != null && !pattern.isEmpty()) { + filters.add("column_name LIKE '%" + pattern + "%'"); + } + } + + @Override + public ExecuteSql getInvalidateItems(Map inputParameter) { + String uniqueKey = inputParameter.get("metric_unique_key"); + ExecuteSql executeSql = new ExecuteSql(); + executeSql.setResultTable("invalidate_items_" + uniqueKey); + executeSql.setSql("SELECT * FROM ${table} WHERE " + String.join(" AND ", filters)); + executeSql.setErrorOutput(true); + return executeSql; + } + + @Override + public ExecuteSql getActualValue(Map inputParameter) { + String uniqueKey = inputParameter.get("metric_unique_key"); + ExecuteSql executeSql = new ExecuteSql(); + executeSql.setResultTable("actual_value_" + uniqueKey); + executeSql.setSql("SELECT COUNT(*) as actual_value_" + uniqueKey + " FROM ${table} WHERE " + String.join(" AND ", filters)); + executeSql.setErrorOutput(false); + return executeSql; + } + + @Override + public List suitableType() { + return Collections.singletonList(DataVinesDataType.STRING_TYPE); + } + + @Override + public MetricDirectionType getDirectionType() { + return MetricDirectionType.POSITIVE; + } +} +``` + +### 注册自定义规则 + +自定义规则需要通过SPI机制注册,具体步骤如下: + +1. 在`src/main/resources/META-INF/services/`目录下创建文件`io.datavines.metric.api.SqlMetric` +2. 在文件中添加自定义规则类的全限定名 + +``` +io.datavines.metric.plugin.CustomDataQualityRule +``` + +### 打包和部署 + +将自定义规则打包成JAR文件,并部署到datavines的插件目录: + +```bash +# 编译打包 +mvn clean package + +# 复制到插件目录 +cp target/datavines-metric-custom-rule-1.0.0.jar $DATAVINES_HOME/plugins/metric/ +``` + +### 配置和使用 + +在datavines配置文件中添加自定义规则的配置: + +```yaml +metric: + rules: + - name: custom_data_quality_rule + zh-name: 自定义数据质量规则 + dimension: CONSISTENCY + type: SINGLE_TABLE +``` + +### 最佳实践 + +开发自定义度量规则时,建议遵循以下最佳实践: + +1. **继承合适的基类**:根据规则类型选择合适的基类继承 +2. **提供清晰的配置项**:为用户提供明确的配置参数 +3. **实现完整的接口方法**:确保所有必需的方法都已实现 +4. **处理异常情况**:妥善处理可能的异常和错误 +5. **编写单元测试**:为自定义规则编写充分的测试用例 +6. **文档化**:提供详细的使用文档和示例 + +```mermaid +graph TD +A[开始] --> B[创建Maven项目] +B --> C[添加datavines-metric依赖] +C --> D[实现SqlMetric接口] +D --> E[实现必要方法] +E --> F[创建SPI配置文件] +F --> G[编译打包] +G --> H[部署到插件目录] +H --> I[配置规则] +I --> J[测试验证] +J --> K[完成] +``` + +**图表来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java) + +**本节来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java) + +## 性能优化策略 + +datavines-metric模块在设计时充分考虑了性能优化,通过多种策略确保在大规模数据场景下的高效执行。 + +### SQL优化 + +模块通过以下方式优化SQL执行性能: + +1. **索引利用**:在生成SQL时考虑索引的使用 +2. **查询简化**:避免不必要的子查询和复杂JOIN +3. **分页处理**:对大数据集采用分页查询 +4. **缓存机制**:缓存常用的查询结果 + +### 执行计划优化 + +```java +@Override +public ExecuteSql getActualValue(Map inputParameter) { + String uniqueKey = inputParameter.get(METRIC_UNIQUE_KEY); + ExecuteSql executeSql = new ExecuteSql(); + executeSql.setResultTable("invalidate_count_" + uniqueKey); + + // 优化:直接使用COUNT(*)而不是SELECT * + String actualValueSql = "select count(1) as actual_value_" + uniqueKey + " from ${invalidate_items_table}"; + executeSql.setSql(actualValueSql); + executeSql.setErrorOutput(false); + return executeSql; +} +``` + +### 并行执行 + +模块支持并行执行多个度量检查,提高整体执行效率: + +```java +// 伪代码:并行执行多个检查 +List> futures = checks.stream() + .map(check -> CompletableFuture.supplyAsync(() -> executeCheck(check))) + .collect(Collectors.toList()); + +List results = futures.stream() + .map(CompletableFuture::join) + .collect(Collectors.toList()); +``` + +### 资源管理 + +通过合理的资源管理策略控制执行资源的使用: + +1. **连接池**:使用数据库连接池管理连接 +2. **线程池**:使用线程池控制并发度 +3. **内存管理**:合理设置JVM参数和内存使用限制 + +### 缓存策略 + +实现多层次的缓存策略: + +1. **配置缓存**:缓存度量规则配置 +2. **元数据缓存**:缓存表结构信息 +3. **结果缓存**:缓存历史检查结果 + +### 监控和调优 + +提供完善的监控和调优机制: + +1. **执行时间监控**:记录每个检查的执行时间 +2. **资源使用监控**:监控CPU、内存、网络等资源使用情况 +3. **性能分析**:提供性能分析工具和报告 + +```mermaid +graph TD +A[性能优化] --> B[SQL优化] +A --> C[执行计划优化] +A --> D[并行执行] +A --> E[资源管理] +A --> F[缓存策略] +A --> G[监控调优] +B --> B1[索引利用] +B --> B2[查询简化] +B --> B3[分页处理] +E --> E1[连接池] +E --> E2[线程池] +E --> E3[内存管理] +F --> F1[配置缓存] +F --> F2[元数据缓存] +F --> F3[结果缓存] +G --> G1[执行时间监控] +G --> G2[资源使用监控] +G --> G3[性能分析] +``` + +**图表来源** +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java) + +**本节来源** +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [BaseSingleTable.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTable.java) + +## 复杂场景使用示例 + +本节提供几个复杂场景下的使用示例,展示datavines-metric模块在实际业务中的应用。 + +### 示例1:电商订单数据质量检查 + +场景描述:电商平台需要确保订单数据的完整性和准确性。 + +```json +{ + "checks": [ + { + "rule": "table_row_count", + "config": { + "table": "orders", + "filter": "order_date = CURRENT_DATE" + }, + "expected": { + "type": "last_7_day_avg", + "days": 7 + }, + "operator": "GTE", + "threshold": 0.9 + }, + { + "rule": "column_not_null", + "config": { + "table": "orders", + "column": "order_id" + }, + "expected": { + "type": "none" + }, + "operator": "EQ", + "threshold": 0 + }, + { + "rule": "column_value_between", + "config": { + "table": "orders", + "column": "amount", + "min_value": 0, + "max_value": 1000000 + }, + "expected": { + "type": "none" + }, + "operator": "EQ", + "threshold": 0 + }, + { + "rule": "multi_table_accuracy", + "config": { + "table": "orders", + "table2": "payments", + "on_clause": "orders.order_id = payments.order_id", + "where_clause": "orders.amount != payments.amount" + }, + "expected": { + "type": "none" + }, + "operator": "EQ", + "threshold": 0 + } + ] +} +``` + +### 示例2:金融交易数据一致性检查 + +场景描述:金融机构需要确保交易数据在不同系统间的一致性。 + +```json +{ + "checks": [ + { + "rule": "multi_table_value_comparison", + "config": { + "table": "trading_system.transactions", + "table2": "settlement_system.transactions", + "key_columns": "transaction_id", + "value_columns": "amount,currency,timestamp" + }, + "expected": { + "type": "none" + }, + "operator": "EQ", + "threshold": 0 + }, + { + "rule": "custom_aggregate_sql", + "config": { + "actual_aggregate_sql": "SELECT SUM(amount) as actual_value FROM trading_system.daily_summary WHERE date = CURRENT_DATE" + }, + "expected": { + "type": "target_table_rows", + "target_table": "settlement_system.daily_summary" + }, + "operator": "EQ", + "threshold": 0 + } + ] +} +``` + +### 示例3:物联网设备数据完整性检查 + +场景描述:物联网平台需要确保设备上报数据的完整性。 + +```json +{ + "checks": [ + { + "rule": "table_freshness", + "config": { + "table": "device_data", + "timestamp_column": "record_time" + }, + "expected": { + "type": "fix", + "value": 300 + }, + "operator": "LTE", + "threshold": 0 + }, + { + "rule": "column_null", + "config": { + "table": "device_data", + "column": "device_id", + "filter": "record_time >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 1 HOUR)" + }, + "expected": { + "type": "none" + }, + "operator": "EQ", + "threshold": 0 + }, + { + "rule": "column_match_regex", + "config": { + "table": "device_data", + "column": "status", + "pattern": "^(online|offline|maintenance)$" + }, + "expected": { + "type": "none" + }, + "operator": "EQ", + "threshold": 0 + } + ] +} +``` + +### 示例4:大数据仓库分层数据校验 + +场景描述:数据仓库需要确保各层数据的一致性。 + +```json +{ + "checks": [ + { + "rule": "multi_table_accuracy", + "config": { + "table": "ods.orders", + "table2": "dwd.orders", + "on_clause": "ods.order_id = dwd.order_id", + "where_clause": "ods.amount != dwd.amount OR ods.status != dwd.status" + }, + "expected": { + "type": "none" + }, + "operator": "EQ", + "threshold": 0 + }, + { + "rule": "custom_aggregate_sql", + "config": { + "actual_aggregate_sql": "SELECT COUNT(*) as actual_value FROM dwd.orders WHERE DATE(order_time) = CURRENT_DATE AND status = 'completed'" + }, + "expected": { + "type": "table_rows", + "table": "ads.daily_order_summary" + }, + "operator": "EQ", + "threshold": 0 + } + ] +} +``` + +```mermaid +graph TD +A[电商订单检查] --> A1[行数检查] +A --> A2[非空检查] +A --> A3[值范围检查] +A --> A4[跨表准确性检查] +B[金融交易检查] --> B1[跨表值比较] +B --> B2[自定义聚合SQL] +C[物联网设备检查] --> C1[数据新鲜度] +C --> C2[空值检查] +C --> C3[正则匹配] +D[数据仓库检查] --> D1[跨表准确性] +D --> D2[自定义聚合SQL] +``` + +**图表来源** +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) +- [ColumnValueBetween.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-value-between/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java) +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) + +**本节来源** +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) +- [ColumnValueBetween.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-value-between/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java) +- [MultiTableAccuracy.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-multi-table-accuracy/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java) +- [CustomAggregateSql.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-custom-aggregate-sql/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java) + +## 结论 + +datavines-metric模块作为DataVines数据质量框架的核心组件,提供了一套完整、灵活且可扩展的数据质量度量解决方案。通过对27种内置检查规则的支持、多种预期值计算策略的实现、精确的结果验证机制和完善的度量配置体系,该模块能够满足各种复杂场景下的数据质量检查需求。 + +模块采用插件化架构设计,通过`SqlMetric`、`ExpectedValue`、`ResultFormula`等标准化接口,实现了高度的可扩展性。开发者可以轻松创建自定义度量规则,并通过SPI机制进行注册和使用。同时,模块在性能优化方面也做了充分考虑,通过SQL优化、并行执行、资源管理和缓存策略等手段,确保在大规模数据场景下的高效执行。 + +未来,datavines-metric模块可以进一步增强机器学习驱动的异常检测能力,支持更复杂的业务规则引擎,并提供更丰富的可视化分析功能,为数据质量管理提供更智能的解决方案。 + +**本节来源** +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [ExpectedValue.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231.md" new file mode 100644 index 00000000..9df36294 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231.md" @@ -0,0 +1,385 @@ +# 内置度量规则 + + +**本文档引用的文件** +- [MetricType.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\MetricType.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [BaseSingleTableColumn.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumn.java) +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [TableRowCount.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-table-row-count\src\main\java\io\datavines\metric\plugin\TableRowCount.java) +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java) +- [ColumnDistinct.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-distinct\src\main\java\io\datavines\metric\plugin\ColumnDistinct.java) +- [ColumnMatchRegex.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-match-regex\src\main\java\io\datavines\metric\plugin\ColumnMatchRegex.java) +- [ColumnInEnums.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-in-enums\src\main\java\io\datavines\metric\plugin\ColumnInEnums.java) +- [ColumnAvg.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg\src\main\java\io\datavines\metric\plugin\ColumnAvg.java) +- [ColumnSum.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-sum\src\main\java\io\datavines\metric\plugin\ColumnSum.java) + + +## 目录 +1. [引言](#引言) +2. [度量规则体系概述](#度量规则体系概述) +3. [核心实现架构](#核心实现架构) +4. [单表列检查规则详解](#单表列检查规则详解) +5. [跨表准确性检查规则](#跨表准确性检查规则) +6. [自定义聚合SQL检查](#自定义聚合SQL检查) +7. [规则选择与性能优化指南](#规则选择与性能优化指南) +8. [复杂场景应用示例](#复杂场景应用示例) +9. [结论](#结论) + +## 引言 + +DataVines系统提供了一套完整的数据质量度量规则体系,旨在通过自动化检查确保数据的准确性、完整性、唯一性和有效性。本文档详细介绍了系统内置的27种预置检查规则,涵盖单表列检查、跨表准确性检查和自定义聚合SQL检查三大类别。通过分析`ColumnNotNull`等具体实现类的代码结构和关键算法,为用户提供规则选择指南和性能优化建议,并提供复杂场景下的规则组合使用示例和最佳实践。 + +## 度量规则体系概述 + +DataVines的度量规则体系基于`SqlMetric`接口构建,通过SPI机制实现插件化扩展。系统定义了四种主要的度量类型,分别对应不同的业务场景: + +```mermaid +graph TD +A[度量类型] --> B[SINGLE_TABLE] +A --> C[SINGLE_TABLE_CUSTOM_SQL] +A --> D[MULTI_TABLE_ACCURACY] +A --> E[MULTI_TABLE_VALUE_COMPARISON] +B --> F[单表检查] +C --> G[自定义SQL检查] +D --> H[跨表准确性检查] +E --> I[两表值比对] +``` + +**图表来源** +- [MetricType.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\MetricType.java) + +**本节来源** +- [MetricType.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\MetricType.java) + +## 核心实现架构 + +度量规则的核心实现基于继承体系,通过抽象基类提供通用功能,具体规则类实现特定业务逻辑。主要的继承关系如下: + +```mermaid +classDiagram +class SqlMetric { +<> ++getName() ++getZhName() ++getDimension() ++getType() ++getInvalidateItems() ++getActualValue() ++validateConfig() ++getConfigMap() +} +class BaseSingleTable { ++invalidateItemsSql ++filters ++configMap ++requiredOptions ++getInvalidateItems() ++getActualValue() ++validateConfig() ++prepare() +} +class BaseSingleTableColumn { ++getConfigMap() ++getLevel() ++isInvalidateItemsCanOutput() +} +class BaseSingleTableColumnNotUseView { ++prepare() +} +SqlMetric <|-- BaseSingleTable +BaseSingleTable <|-- BaseSingleTableColumn +BaseSingleTableColumn <|-- BaseSingleTableColumnNotUseView +``` + +**图表来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [BaseSingleTableColumn.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumn.java) + +**本节来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [BaseSingleTableColumn.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumn.java) + +## 单表列检查规则详解 + +单表列检查规则是数据质量检查的基础,主要针对单个表的特定列进行各种约束验证。这些规则继承自`BaseSingleTableColumn`类,实现了列级别的数据质量检查。 + +### 非空检查 (ColumnNotNull) + +非空检查用于验证指定列中是否存在空值,确保数据的完整性。 + +```mermaid +flowchart TD +Start([开始]) --> Prepare["准备检查参数"] +Prepare --> AddFilter["添加非空过滤条件"] +AddFilter --> BuildSQL["构建无效项查询SQL"] +BuildSQL --> Execute["执行查询"] +Execute --> Count["统计无效项数量"] +Count --> End([结束]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图表来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) + +**本节来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) + +### 唯一性检查 (ColumnUnique) + +唯一性检查用于验证指定列中的值是否唯一,防止重复数据的产生。 + +```mermaid +flowchart TD +Start([开始]) --> Prepare["准备检查参数"] +Prepare --> AddGroupBy["添加GROUP BY和HAVING子句"] +AddGroupBy --> BuildSQL["构建重复值查询SQL"] +BuildSQL --> Execute["执行查询"] +Execute --> Count["统计重复值数量"] +Count --> End([结束]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图表来源** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) + +**本节来源** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) + +### 值范围检查 (ColumnValueBetween) + +值范围检查用于验证指定列的值是否在预设的最小值和最大值范围内。 + +```mermaid +flowchart TD +Start([开始]) --> CheckConfig["检查配置参数"] +CheckConfig --> AddMinFilter{"配置了最小值?"} +AddMinFilter --> |是| AddMin["添加大于等于过滤"] +AddMinFilter --> |否| AddMaxFilter +AddMaxFilter{"配置了最大值?"} +AddMaxFilter --> |是| AddMax["添加小于等于过滤"] +AddMaxFilter --> |否| BuildSQL +AddMin --> BuildSQL +AddMax --> BuildSQL +BuildSQL --> Execute["执行查询"] +Execute --> Count["统计越界值数量"] +Count --> End([结束]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图表来源** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) + +**本节来源** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) + +### 正则表达式检查 (ColumnMatchRegex) + +正则表达式检查用于验证指定列的值是否符合预设的正则表达式模式。 + +```mermaid +flowchart TD +Start([开始]) --> CheckConfig["检查配置参数"] +CheckConfig --> ValidateRegex{"正则表达式有效?"} +ValidateRegex --> |是| AddFilter["添加正则匹配过滤"] +ValidateRegex --> |否| Error["返回配置错误"] +AddFilter --> BuildSQL["构建不匹配项查询SQL"] +BuildSQL --> Execute["执行查询"] +Execute --> Count["统计不匹配项数量"] +Count --> End([结束]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图表来源** +- [ColumnMatchRegex.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-match-regex\src\main\java\io\datavines\metric\plugin\ColumnMatchRegex.java) + +**本节来源** +- [ColumnMatchRegex.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-match-regex\src\main\java\io\datavines\metric\plugin\ColumnMatchRegex.java) + +### 枚举值检查 (ColumnInEnums) + +枚举值检查用于验证指定列的值是否属于预设的枚举值列表。 + +```mermaid +flowchart TD +Start([开始]) --> CheckConfig["检查配置参数"] +CheckConfig --> ValidateEnums{"枚举值列表有效?"} +ValidateEnums --> |是| AddFilter["添加IN子句过滤"] +ValidateEnums --> |否| Error["返回配置错误"] +AddFilter --> BuildSQL["构建非法枚举值查询SQL"] +BuildSQL --> Execute["执行查询"] +Execute --> Count["统计非法枚举值数量"] +Count --> End([结束]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图表来源** +- [ColumnInEnums.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-in-enums\src\main\java\io\datavines\metric\plugin\ColumnInEnums.java) + +**本节来源** +- [ColumnInEnums.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-in-enums\src\main\java\io\datavines\metric\plugin\ColumnInEnums.java) + +### 数值统计检查 + +数值统计检查包括平均值、总值、标准差等统计指标的计算。 + +```mermaid +flowchart TD +Start([开始]) --> CheckType{"列类型为数值型?"} +CheckType --> |是| BuildSQL["构建统计查询SQL"] +CheckType --> |否| Error["返回类型不支持"] +BuildSQL --> AddFilter["添加过滤条件"] +AddFilter --> Execute["执行查询"] +Execute --> Return["返回统计结果"] +Return --> End([结束]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图表来源** +- [ColumnAvg.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg\src\main\java\io\datavines\metric\plugin\ColumnAvg.java) +- [ColumnSum.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-sum\src\main\java\io\datavines\metric\plugin\ColumnSum.java) + +**本节来源** +- [ColumnAvg.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-avg\src\main\java\io\datavines\metric\plugin\ColumnAvg.java) +- [ColumnSum.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-sum\src\main\java\io\datavines\metric\plugin\ColumnSum.java) + +## 跨表准确性检查规则 + +跨表准确性检查规则用于验证不同表之间的数据一致性,确保数据在不同系统或不同版本之间保持准确。 + +### 跨表准确性检查 (MultiTableAccuracy) + +跨表准确性检查通过LEFT JOIN操作比较源表和目标表的数据,识别缺失或不匹配的记录。 + +```mermaid +sequenceDiagram +participant Source as 源表 +participant Target as 目标表 +participant Check as 检查规则 +participant Result as 结果 +Check->>Source : SELECT * FROM ${table} +Check->>Target : SELECT * FROM ${table2} +Check->>Check : LEFT JOIN ON ${on_clause} +Check->>Check : WHERE ${where_clause} +Check->>Result : 返回不匹配的记录 +Result->>Check : 统计不匹配记录数量 +``` + +**图表来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) + +**本节来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) + +### 两表值比对 (MultiTableValueComparison) + +两表值比对规则用于比较两个表中特定字段的值是否一致。 + +**本节来源** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java) + +## 自定义聚合SQL检查 + +自定义聚合SQL检查允许用户编写自定义的SQL查询来实现复杂的度量逻辑。 + +### 自定义聚合SQL (CustomAggregateSql) + +自定义聚合SQL规则允许用户直接提供SQL语句进行数据质量检查。 + +```mermaid +flowchart TD +Start([开始]) --> CheckConfig["检查配置参数"] +CheckConfig --> ValidateSQL{"SQL语句有效?"} +ValidateSQL --> |是| ModifySQL["修改SQL别名"] +ValidateSQL --> |否| Error["返回配置错误"] +ModifySQL --> Execute["执行自定义SQL"] +Execute --> Return["返回查询结果"] +Return --> End([结束]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图表来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) + +## 规则选择与性能优化指南 + +### 规则选择指南 + +根据不同的业务场景和数据特征,选择合适的度量规则: + +| 业务场景 | 推荐规则 | 说明 | +|---------|---------|------| +| 数据完整性验证 | 非空检查、值范围检查 | 确保关键字段不为空且在合理范围内 | +| 数据一致性验证 | 跨表准确性检查 | 确保不同系统间数据同步一致 | +| 数据有效性验证 | 枚举值检查、正则表达式检查 | 确保数据符合业务规则 | +| 数据统计分析 | 平均值检查、总值检查 | 获取数据的统计特征 | + +### 性能优化建议 + +1. **合理使用过滤条件**:通过配置`filter`参数减少查询数据量 +2. **避免全表扫描**:确保被检查的列上有适当的索引 +3. **批量处理**:对于多表检查,考虑使用批处理方式 +4. **结果缓存**:对于频繁执行的检查,考虑缓存结果 + +**本节来源** +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [TableRowCount.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-table-row-count\src\main\java\io\datavines\metric\plugin\TableRowCount.java) + +## 复杂场景应用示例 + +### 组合规则应用 + +在实际业务中,往往需要组合多个规则来全面评估数据质量: + +```mermaid +flowchart TD +A[用户信息表] --> B[非空检查] +A --> C[唯一性检查] +A --> D[正则表达式检查] +A --> E[值范围检查] +B --> F[检查用户ID不为空] +C --> G[检查手机号唯一] +D --> H[检查邮箱格式] +E --> I[检查年龄范围] +J[订单表] --> K[跨表准确性检查] +K --> L[与用户表关联验证] +M[财务表] --> N[自定义聚合SQL] +N --> O[复杂业务规则验证] +``` + +**图表来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnMatchRegex.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-match-regex\src\main\java\io\datavines\metric\plugin\ColumnMatchRegex.java) +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) + +**本节来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnMatchRegex.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-match-regex\src\main\java\io\datavines\metric\plugin\ColumnMatchRegex.java) +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) + +## 结论 + +DataVines的内置度量规则体系提供了全面的数据质量检查能力,通过27种预置规则覆盖了数据质量的各个方面。系统采用模块化设计,通过`SqlMetric`接口和继承体系实现了规则的可扩展性和可维护性。用户可以根据具体业务需求选择合适的规则,并通过组合使用实现复杂的数据质量验证。在实际应用中,应结合性能优化建议,合理配置规则参数,以达到最佳的检查效果。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231.md" new file mode 100644 index 00000000..4f629f9a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231.md" @@ -0,0 +1,400 @@ +# 单表检查规则 + + +**本文档引用的文件** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [DataVinesDataType.java](file://datavines-common\src\main\java\io\datavines\common\enums\DataVinesDataType.java) +- [MetricDimension.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\MetricDimension.java) + + +## 目录 +1. [引言](#引言) +2. [核心单表检查规则](#核心单表检查规则) + 1. [非空检查](#非空检查) + 2. [唯一性检查](#唯一性检查) + 3. [值范围检查](#值范围检查) + 4. [重复值检查](#重复值检查) +3. [规则配置与执行逻辑](#规则配置与执行逻辑) +4. [实现类分析](#实现类分析) +5. [规则选择指南与性能优化](#规则选择指南与性能优化) +6. [复杂场景下的规则组合使用](#复杂场景下的规则组合使用) +7. [最佳实践](#最佳实践) + +## 引言 +DataVines 是一个数据质量管理系统,提供多种单表列级质量检查规则。这些规则用于验证数据的完整性、有效性、唯一性等关键质量维度。本文档将详细介绍非空检查、唯一性检查、值范围检查和重复值检查等核心单表检查规则,包括它们的业务场景、配置参数、执行逻辑以及具体实现。 + +## 核心单表检查规则 + +### 非空检查 +非空检查(`column_not_null`)用于验证指定列中是否存在空值,确保数据的完整性。 + +**业务场景**: +在数据录入或ETL过程中,某些关键字段如用户ID、订单号等必须有值,不能为空。非空检查可以确保这些关键字段的数据完整性。 + +**配置参数**: +- `column`:要检查的列名(必填) +- `table`:目标表名(必填) +- `filter`:可选的过滤条件 + +**执行逻辑**: +该规则通过生成SQL查询来检查指定列中不为空的记录数量。核心SQL片段为 `${column} is not null`,它会被嵌入到完整的查询语句中进行执行。 + +```mermaid +flowchart TD +Start([开始]) --> ValidateConfig["验证配置参数"] +ValidateConfig --> BuildSQL["构建检查SQL"] +BuildSQL --> ExecuteSQL["执行SQL查询"] +ExecuteSQL --> CheckResult["检查结果"] +CheckResult --> |无空值| Success["检查通过"] +CheckResult --> |存在空值| Failure["检查失败"] +Success --> End([结束]) +Failure --> End +``` + +**图源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java#L60-L65) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L93-L95) + +**节源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) + +### 唯一性检查 +唯一性检查(`column_unique`)用于验证指定列中的值是否都是唯一的,即没有重复值。 + +**业务场景**: +主键字段、唯一标识符等列需要保证其值的唯一性。例如,用户表中的邮箱地址或身份证号通常需要是唯一的。 + +**配置参数**: +- `column`:要检查的列名(必填) +- `table`:目标表名(必填) +- `filter`:可选的过滤条件 + +**执行逻辑**: +该规则通过分组和计数来识别重复值。核心SQL片段为 `group by ${column} having count(1) = 1`,它会筛选出那些只出现一次的值,从而确认列的唯一性。 + +```mermaid +flowchart TD +Start([开始]) --> ValidateConfig["验证配置参数"] +ValidateConfig --> BuildSQL["构建分组查询SQL"] +BuildSQL --> ExecuteSQL["执行SQL查询"] +ExecuteSQL --> GroupBy["按列值分组"] +GroupBy --> Count["统计每组记录数"] +Count --> Filter["筛选计数为1的组"] +Filter --> CheckCount["检查结果数量"] +CheckCount --> |等于总记录数| Unique["值唯一"] +CheckCount --> |小于总记录数| NotUnique["存在重复值"] +Unique --> Success["检查通过"] +NotUnique --> Failure["检查失败"] +Success --> End([结束]) +Failure --> End +``` + +**图源** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java#L62-L70) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L77-L79) + +**节源** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) + +### 值范围检查 +值范围检查(`column_value_between`)用于验证指定列的值是否在预定义的最小值和最大值范围内。 + +**业务场景**: +数值型字段如年龄、价格、分数等通常有合理的取值范围。例如,年龄应在0-150之间,价格不能为负数。 + +**配置参数**: +- `column`:要检查的列名(必填) +- `table`:目标表名(必填) +- `min`:最小值(可选) +- `max`:最大值(可选) +- `filter`:可选的过滤条件 + +**执行逻辑**: +该规则通过比较操作符来限制值的范围。核心SQL片段包括 `${column} >= ${min}` 和 `${column} <= ${max}`,它们会被组合成WHERE子句来过滤出不符合范围的记录。 + +```mermaid +flowchart TD +Start([开始]) --> ValidateConfig["验证配置参数"] +ValidateConfig --> CheckMin["检查是否配置最小值"] +CheckMin --> |是| AddMinCondition["添加 >= 条件"] +CheckMin --> |否| SkipMin +AddMinCondition --> BuildSQL +SkipMin --> CheckMax +CheckMax --> |是| AddMaxCondition["添加 <= 条件"] +CheckMax --> |否| SkipMax +AddMaxCondition --> BuildSQL +SkipMax --> BuildSQL +BuildSQL["构建范围检查SQL"] --> ExecuteSQL["执行SQL查询"] +ExecuteSQL --> CheckResult["检查结果"] +CheckResult --> |所有值在范围内| Success["检查通过"] +CheckResult --> |存在越界值| Failure["检查失败"] +Success --> End([结束]) +Failure --> End +``` + +**图源** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L64-L75) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L113-L118) + +**节源** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) + +### 重复值检查 +重复值检查(`column_duplicate`)用于识别和报告指定列中存在的重复值。 + +**业务场景**: +在数据清洗和去重过程中,需要找出并处理重复的记录。例如,客户信息表中可能存在重复的手机号或邮箱。 + +**配置参数**: +- `column`:要检查的列名(必填) +- `table`:目标表名(必填) +- `filter`:可选的过滤条件 + +**执行逻辑**: +该规则通过分组和HAVING子句来直接找出重复值。核心SQL片段为 `group by ${column} having count(${column}) > 1`,它会返回所有出现次数大于1的值。 + +```mermaid +flowchart TD +Start([开始]) --> ValidateConfig["验证配置参数"] +ValidateConfig --> BuildSQL["构建重复值查询SQL"] +BuildSQL --> ExecuteSQL["执行SQL查询"] +ExecuteSQL --> GroupBy["按列值分组"] +GroupBy --> Count["统计每组记录数"] +Count --> Filter["筛选计数大于1的组"] +Filter --> GetDuplicateValues["获取重复值列表"] +GetDuplicateValues --> CheckEmpty["检查结果是否为空"] +CheckEmpty --> |为空| NoDuplicates["无重复值"] +CheckEmpty --> |不为空| HasDuplicates["存在重复值"] +NoDuplicates --> Success["检查通过"] +HasDuplicates --> Failure["检查失败"] +Success --> End([结束]) +Failure --> End +``` + +**图源** +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java#L62-L71) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L81-L83) + +**节源** +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) + +## 规则配置与执行逻辑 +单表检查规则的配置和执行遵循统一的框架。所有规则都实现了 `SqlMetric` 接口,并继承自 `BaseSingleTable` 或其子类。 + +**配置流程**: +1. **参数验证**:通过 `validateConfig` 方法检查必需参数是否提供。 +2. **参数准备**:`prepare` 方法将配置参数转换为内部使用的过滤条件。 +3. **SQL生成**:根据配置生成用于检查无效项和计算实际值的SQL语句。 + +**执行流程**: +1. **获取无效项**:执行 `getInvalidateItems` 生成的SQL,获取不符合规则的数据行。 +2. **计算实际值**:执行 `getActualValue` 或 `getDirectActualValue` 生成的SQL,计算违规数据的数量。 +3. **结果评估**:将实际值与预期值进行比较,判断规则是否通过。 + +```mermaid +classDiagram +class SqlMetric { +<> ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++CheckResult validateConfig(Map~String,Object~) ++void prepare(Map~String,String~) +} +class BaseSingleTable { +-StringBuilder invalidateItemsSql +-String[] filters +-HashMap~String,ConfigItem~ configMap +-Set~String~ requiredOptions ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++CheckResult validateConfig(Map~String,Object~) ++void prepare(Map~String,String~) ++ConnectorFactory getConnectorFactory(Map~String,String~) +} +class BaseSingleTableColumnNotUseView { ++BaseSingleTableColumnNotUseView() ++MetricLevel getLevel() ++ExecuteSql getDirectActualValue(Map~String,String~) +} +class ColumnNotNull { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnUnique { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnValueBetween { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnDuplicate { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +SqlMetric <|-- BaseSingleTable +BaseSingleTable <|-- BaseSingleTableColumnNotUseView +BaseSingleTableColumnNotUseView <|-- ColumnNotNull +BaseSingleTableColumnNotUseView <|-- ColumnUnique +BaseSingleTableColumnNotUseView <|-- ColumnValueBetween +BaseSingleTableColumnNotUseView <|-- ColumnDuplicate +``` + +**图源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java) + +**节源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) + +## 实现类分析 +### ColumnNotNull 实现分析 +`ColumnNotNull` 类实现了非空检查的核心逻辑。它继承自 `BaseSingleTableColumnNotUseView`,并重写了关键方法。 + +**关键方法**: +- `getName()`:返回规则的英文标识符 `column_not_null`。 +- `getZhName()`:返回规则的中文名称 "非空检查"。 +- `getDimension()`:返回质量维度 `EFFECTIVENESS`(有效性)。 +- `getType()`:返回规则类型 `SINGLE_TABLE`(单表)。 +- `prepare()`:准备检查逻辑,将 `columnNotNull()` SQL片段添加到过滤器中。 + +**执行流程**: +1. 调用 `prepare` 方法,根据配置构建过滤条件。 +2. 调用 `getInvalidateItems` 获取所有非空值的记录。 +3. 调用 `getDirectActualValue` 计算非空值的数量。 + +```mermaid +sequenceDiagram +participant User as 用户 +participant Rule as ColumnNotNull规则 +participant Base as BaseSingleTable +participant Script as MetricScript +User->>Rule : 配置参数 (column, table) +Rule->>Rule : prepare(config) +Rule->>Script : getConnectorFactory().getMetricScript().columnNotNull() +Script-->>Rule : 返回 "${column} is not null" +Rule->>Base : super.prepare(config) +Base->>Base : addFiltersIntoInvalidateItemsSql() +Rule->>Rule : getDirectActualValue(inputParameter) +Base->>Base : 构建 count(1) 查询 +Base-->>User : 返回检查结果 +``` + +**图源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) + +**节源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) + +## 规则选择指南与性能优化 +### 规则选择指南 +选择合适的检查规则应基于数据的业务含义和质量要求: + +| 规则类型 | 适用数据类型 | 适用场景 | +|--------|-----------|--------| +| 非空检查 | 所有类型 | 关键字段完整性验证 | +| 唯一性检查 | 数值、字符串、日期时间 | 主键、唯一标识符验证 | +| 值范围检查 | 数值、日期时间 | 数值合理性验证 | +| 重复值检查 | 所有类型 | 数据去重、清洗 | + +**选择建议**: +- 对于主键字段,应同时使用**非空检查**和**唯一性检查**。 +- 对于业务关键字段(如价格、数量),应使用**值范围检查**。 +- 在数据导入后,应运行**重复值检查**以确保数据清洁。 + +### 性能优化建议 +1. **索引优化**:为被检查的列创建索引,特别是用于唯一性检查和重复值检查的列。 +2. **分区表查询**:对于大表,利用分区信息缩小查询范围。 +3. **采样检查**:对于超大表,可先进行采样检查,再决定是否全量检查。 +4. **批量执行**:将多个规则组合成一个作业批量执行,减少系统开销。 + +## 复杂场景下的规则组合使用 +在实际应用中,往往需要组合多个规则来满足复杂的质量要求。 + +**示例:用户信息表质量检查** +```json +{ + "rules": [ + { + "type": "column_not_null", + "config": { + "column": "user_id", + "table": "users" + } + }, + { + "type": "column_unique", + "config": { + "column": "email", + "table": "users" + } + }, + { + "type": "column_value_between", + "config": { + "column": "age", + "table": "users", + "min": "0", + "max": "150" + } + }, + { + "type": "column_duplicate", + "config": { + "column": "phone", + "table": "users" + } + } + ] +} +``` + +此组合确保了用户ID不为空、邮箱唯一、年龄合理且手机号无重复。 + +## 最佳实践 +1. **分层检查**:先进行非空检查,再进行其他更复杂的检查。 +2. **配置复用**:将常用的检查配置保存为模板,便于重复使用。 +3. **定期执行**:将数据质量检查纳入日常ETL流程,实现自动化监控。 +4. **结果分析**:不仅关注检查是否通过,更要分析违规数据的模式和原因。 +5. **渐进式实施**:从关键表和关键字段开始,逐步扩展到整个数据仓库。 + +通过合理选择和组合这些单表检查规则,可以有效提升数据质量,为数据分析和决策提供可靠的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\345\224\257\344\270\200\346\200\247_\351\207\215\345\244\215\345\200\274\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\345\224\257\344\270\200\346\200\247_\351\207\215\345\244\215\345\200\274\346\243\200\346\237\245.md" new file mode 100644 index 00000000..6c9fdf13 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\345\224\257\344\270\200\346\200\247_\351\207\215\345\244\215\345\200\274\346\243\200\346\237\245.md" @@ -0,0 +1,171 @@ +# 唯一性/重复值检查 + + +**本文档引用的文件** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) +- [ConnectorFactory.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\ConnectorFactory.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) + + +## 目录 +1. [简介](#简介) +2. [核心实现机制](#核心实现机制) +3. [算法复杂度与性能分析](#算法复杂度与性能分析) +4. [配置参数说明](#配置参数说明) +5. [使用场景示例](#使用场景示例) +6. [与其他质量规则的协同应用](#与其他质量规则的协同应用) +7. [不同数据类型的优化策略](#不同数据类型的优化策略) +8. [常见陷阱规避方法](#常见陷阱规避方法) +9. [总结](#总结) + +## 简介 +DataVines平台提供了两种关键的数据质量检查规则:`ColumnUnique`(唯一性检查)和`ColumnDuplicate`(重复值检查),用于检测数据表中指定列的唯一性约束是否被违反。这两种规则通过SQL查询实现,能够识别出违反唯一性约束的数据记录,并提供详细的诊断信息。本文档将深入分析这两种规则的实现机制、性能特征、配置方式和最佳实践。 + +## 核心实现机制 + +`ColumnUnique`和`ColumnDuplicate`规则均继承自`BaseSingleTableColumnNotUseView`类,该类又继承自`BaseSingleTable`基类。这种继承结构实现了功能的分层和复用。 + +`ColumnUnique`规则的核心实现是通过在`prepare`方法中构建一个SQL查询语句,该语句使用`GROUP BY`和`HAVING COUNT(1) = 1`子句来筛选出只出现一次的值,从而确认其唯一性。其`invalidateItemsSql`初始值为`"select ${column} from ${table}"`,在`prepare`方法中会根据配置添加过滤条件和分组去重逻辑。 + +`ColumnDuplicate`规则的实现机制与`ColumnUnique`类似,但其目标是找出重复值。它在`prepare`方法中构建的SQL查询使用`GROUP BY`和`HAVING COUNT(${column}) > 1`子句来筛选出出现次数大于1的值。其`getDirectionType`方法返回`NEGATIVE`,表明这是一个负面指标,值越小越好。 + +两种规则都通过`getConnectorFactory(config)`方法获取当前数据源类型的`ConnectorFactory`,然后调用其`getMetricScript()`方法来获取与数据库方言相关的SQL片段。这确保了生成的SQL语句能够兼容不同的数据库系统(如MySQL、PostgreSQL、Oracle等)。 + +**Section sources** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java#L31-L78) +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java#L30-L83) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java#L27-L60) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L77-L82) + +## 算法复杂度与性能分析 + +这两种规则的底层算法复杂度主要取决于数据库的执行计划和索引使用情况。 + +### 算法复杂度 +- **时间复杂度**:在最坏情况下,数据库需要对整个目标列进行全表扫描和排序(或哈希)操作来执行`GROUP BY`。因此,时间复杂度为O(n log n),其中n是表中的行数。如果数据库优化器使用哈希聚合,复杂度可能接近O(n)。 +- **空间复杂度**:数据库需要在内存或临时表空间中存储分组结果,空间复杂度为O(k),其中k是目标列中不同值的数量。在最坏情况下(所有值都唯一),k等于n。 + +### 索引利用情况 +这两种规则的性能高度依赖于目标列上是否存在索引。 +- **有索引的情况**:如果目标列上有唯一索引(Unique Index)或主键索引(Primary Key Index),数据库可以快速验证唯一性,性能极佳。即使没有唯一索引,普通的B-Tree索引也能显著加速`GROUP BY`操作。 +- **无索引的情况**:如果没有索引,数据库必须执行全表扫描,性能会随着数据量的增长而急剧下降,尤其是在处理大数据量时。 + +### 大数据量下的性能表现 +在处理大数据量时,这些规则可能会面临性能瓶颈: +1. **内存压力**:`GROUP BY`操作需要大量内存来存储中间结果。如果内存不足,数据库会使用磁盘临时表,导致性能大幅下降。 +2. **执行时间长**:对于包含数亿行记录的表,查询可能需要数分钟甚至更长时间才能完成。 +3. **资源竞争**:长时间运行的查询会占用数据库连接和计算资源,可能影响其他业务操作。 + +为了优化大数据量下的性能,建议: +- 始终在被检查的列上创建适当的索引。 +- 使用`filter`参数缩小检查范围,例如只检查最近一天的数据。 +- 在非高峰时段执行这些检查任务。 + +**Section sources** +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L50-L68) +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java#L69) +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java#L70) + +## 配置参数说明 + +`ColumnUnique`和`ColumnDuplicate`规则共享一套核心配置参数: + +```properties +# 必需参数 +table=your_table_name # 要检查的表名 +column=your_column_name # 要检查唯一性的列名 + +# 可选参数 +filter=your_filter_condition # SQL WHERE子句的过滤条件,用于限定检查范围 +src_connector_type=your_db_type # 数据源类型,如mysql, postgres, oracle等 +``` + +- **`table`**: 指定要进行唯一性检查的目标表的名称。这是必需参数。 +- **`column`**: 指定要在目标表中检查唯一性的具体列名。这也是必需参数。 +- **`filter`**: 这是一个强大的可选参数,允许用户指定一个SQL WHERE子句来过滤数据。例如,`filter="status = 'active' AND create_time > '2023-01-01'"`将只检查状态为“active”且创建时间在2023年之后的记录。这在处理分区表或增量数据时非常有用。 +- **`src_connector_type`**: 指定数据源的类型,系统会根据此类型加载相应的`ConnectorFactory`和`MetricScript`,以生成符合该数据库语法的SQL语句。 + +**Section sources** +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L43-L48) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java#L31-L33) + +## 使用场景示例 + +### 场景一:检查用户表的邮箱唯一性 +在用户注册系统中,确保每个用户的邮箱地址是唯一的至关重要。 + +```json +{ + "table": "users", + "column": "email", + "filter": "status = 'active'" +} +``` +此配置将检查`users`表中所有状态为“active”的用户的`email`列是否存在重复值。 + +### 场景二:检查订单表的订单号唯一性 +订单号是业务系统中的核心标识,必须保证全局唯一。 + +```json +{ + "table": "orders", + "column": "order_id", + "filter": "DATE(create_time) = CURRENT_DATE" +} +``` +此配置将检查当天创建的所有订单的`order_id`是否唯一,适用于每日数据质量监控。 + +### 场景三:检查复合业务键的唯一性 +虽然`ColumnUnique`和`ColumnDuplicate`是单列检查,但可以通过自定义SQL或使用`MultiColumnDuplicate`规则来检查多列组合的唯一性。例如,检查“日期+地区”组合的唯一性。 + +**Section sources** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java) +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java) + +## 与其他质量规则的协同应用 + +`ColumnUnique`和`ColumnDuplicate`规则可以与其他数据质量规则结合使用,形成一个全面的数据质量监控体系。 + +- **与`ColumnNotNull`规则协同**:在检查唯一性之前,通常需要确保该列不允许为空。可以先使用`ColumnNotNull`规则检查非空约束,再使用`ColumnUnique`规则检查唯一性。这两个规则的组合等效于数据库中的`UNIQUE NOT NULL`约束。 +- **与`ColumnInEnums`规则协同**:对于枚举类型的列,可以先检查其值是否在预定义的枚举列表中,再检查其唯一性。例如,检查“优惠券代码”是否有效且唯一。 +- **与`TableFreshness`规则协同**:将唯一性检查与数据新鲜度检查结合,可以确保数据不仅唯一,而且是最新的。例如,检查当天的交易流水号是否唯一且数据已成功加载。 + +通过规则引擎的组合,可以定义复杂的数据质量校验流程,实现从原子校验到整体数据健康度的全面评估。 + +**Section sources** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) + +## 不同数据类型的优化策略 + +`ColumnUnique`和`ColumnDuplicate`规则支持多种数据类型,包括数值型(NUMERIC_TYPE)、字符串型(STRING_TYPE)和日期时间型(DATE_TIME_TYPE)。针对不同数据类型,可以采取不同的优化策略: + +- **字符串类型**:对于长文本字段(如VARCHAR(255)或TEXT),直接进行`GROUP BY`可能会非常低效。建议: + - 使用`filter`参数只检查关键子集。 + - 考虑对字符串进行哈希处理(如果平台支持自定义SQL),然后对哈希值进行唯一性检查。 +- **数值类型**:数值类型的比较和排序效率通常很高,是性能最好的情况。无需特殊优化。 +- **日期时间类型**:日期时间类型通常与时间范围过滤结合使用。应始终使用`filter`参数(如`create_time > '2023-01-01'`)来限制检查范围,并确保该列上有索引。 + +**Section sources** +- [ColumnUnique.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-unique\src\main\java\io\datavines\metric\plugin\ColumnUnique.java#L75-L77) +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java#L75-L77) + +## 常见陷阱规避方法 + +在使用这些规则时,需要注意以下常见陷阱: + +1. **忽略NULL值**:在SQL中,`NULL`值与任何值(包括另一个`NULL`)都不相等。因此,`GROUP BY`会将所有`NULL`值分到一组。如果一个列有多个`NULL`值,`ColumnDuplicate`规则会将其报告为重复值。如果业务上允许`NULL`值存在且不认为是重复,应在`filter`中排除`NULL`值,例如`filter="${column} IS NOT NULL"`。 +2. **大小写敏感性**:字符串的唯一性检查受数据库的排序规则(collation)影响。在大小写不敏感的排序规则下,"ABC"和"abc"被视为相同。需要根据业务需求确认排序规则是否合适。 +3. **性能瓶颈**:如前所述,对大表进行全表扫描的代价很高。务必通过索引和`filter`参数来优化性能。 +4. **配置错误**:确保`src_connector_type`配置正确,否则系统可能无法找到对应的`ConnectorFactory`,导致SQL生成失败。 + +**Section sources** +- [ColumnDuplicate.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-duplicate\src\main\java\io\datavines\metric\plugin\ColumnDuplicate.java#L65-L67) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java#L78-L80) + +## 总结 +`ColumnUnique`和`ColumnDuplicate`是DataVines平台中用于保障数据唯一性的核心规则。它们通过灵活的SQL生成机制和可插拔的数据库适配器,实现了跨数据库的兼容性。其性能表现与数据库索引和数据量密切相关,合理使用`filter`参数和索引是保证其高效运行的关键。通过与其他质量规则协同,可以构建出强大而全面的数据质量监控体系,有效预防和发现数据质量问题。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\346\225\260\345\200\274\350\214\203\345\233\264\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\346\225\260\345\200\274\350\214\203\345\233\264\346\243\200\346\237\245.md" new file mode 100644 index 00000000..5d8fd44f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\346\225\260\345\200\274\350\214\203\345\233\264\346\243\200\346\237\245.md" @@ -0,0 +1,208 @@ +# 数值范围检查 + + +**本文档引用的文件** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [ColumnMin.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-min\src\main\java\io\datavines\metric\plugin\ColumnMin.java) +- [ColumnMax.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-max\src\main\java\io\datavines\metric\plugin\ColumnMax.java) +- [BaseSingleTableColumn.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumn.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) +- [JdbcMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcMetricScript.java) + + +## 目录 +1. [引言](#引言) +2. [核心规则实现](#核心规则实现) +3. [SQL生成策略](#sql生成策略) +4. [数据类型兼容性](#数据类型兼容性) +5. [业务应用场景](#业务应用场景) +6. [性能优化建议](#性能优化建议) +7. [动态阈值配置](#动态阈值配置) +8. [时间序列数据处理](#时间序列数据处理) +9. [结论](#结论) + +## 引言 + +数值范围检查是数据质量保障体系中的关键环节,主要用于验证数据列中的值是否在预期的合理范围内。本系统提供了三种核心的数值范围检查规则:`ColumnValueBetween`(值范围检查)、`ColumnMin`(最小值检查)和`ColumnMax`(最大值检查),这些规则能够有效识别异常值、防止数据污染,确保数据的准确性和可靠性。本文档将深入介绍这些规则的业务应用、实现细节以及最佳实践。 + +## 核心规则实现 + +### ColumnValueBetween 规则 + +`ColumnValueBetween` 规则用于检查指定列的值是否在给定的最小值和最大值之间。该规则通过配置 `min` 和 `max` 参数来定义范围边界。 + +**实现细节**: +- **配置项**:该规则在构造函数中注册了 `min` 和 `max` 两个配置项,分别对应“最小值”和“最大值”。 +- **准备阶段**:在 `prepare` 方法中,根据配置的 `min` 和 `max` 值,动态地向过滤器列表 `filters` 中添加相应的 SQL 片段。如果配置了 `min`,则添加 `columnGteMin()` 生成的 SQL;如果配置了 `max`,则添加 `columnLteMax()` 生成的 SQL。 +- **数据类型支持**:该规则支持数值型(NUMERIC_TYPE)、字符串型(STRING_TYPE)和日期时间型(DATE_TIME_TYPE)等多种数据类型。 + +```mermaid +classDiagram +class ColumnValueBetween { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++void prepare(Map config) ++List suitableType() +} +class BaseSingleTableColumnNotUseView { ++Map configMap ++Set requiredOptions ++List filters ++void prepare(Map config) ++ExecuteSql getDirectActualValue(Map inputParameter) +} +ColumnValueBetween --|> BaseSingleTableColumnNotUseView : 继承 +``` + +**类图来源** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) + +**本节来源** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L31-L82) + +### ColumnMin 和 ColumnMax 规则 + +`ColumnMin` 和 `ColumnMax` 规则分别用于获取指定列的最小值和最大值,通常作为基准值或用于与其他值进行比较。 + +**实现细节**: +- **继承关系**:这两个规则都继承自 `BaseSingleTableColumn` 类,共享了列名(`column`)配置项的处理逻辑。 +- **SQL生成**:在 `getActualValue` 方法中,通过调用 `getConnectorFactory(inputParameter).getMetricScript()` 获取对应的 `MetricScript` 实例,然后调用 `minActualValue(uniqueKey)` 或 `maxActualValue(uniqueKey)` 方法生成获取最小值或最大值的 SQL 语句。 +- **数据类型支持**:这两个规则仅支持数值型(NUMERIC_TYPE)数据,因为对字符串或日期类型求最小/最大值在某些场景下可能没有实际意义或需要特殊处理。 + +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant 规则 as ColumnMin/Max +participant 工厂 as ConnectorFactory +participant 脚本 as MetricScript +participant 执行器 as SQL执行器 +用户->>规则 : 配置并执行检查 +规则->>规则 : prepare(config) +规则->>工厂 : getConnectorFactory(inputParameter) +工厂-->>规则 : 返回Connector +规则->>脚本 : getMetricScript() +脚本-->>规则 : 返回MetricScript实例 +规则->>脚本 : minActualValue()/maxActualValue() +脚本-->>规则 : 返回SQL字符串 +规则->>执行器 : 执行生成的SQL +执行器-->>用户 : 返回最小值/最大值结果 +``` + +**序列图来源** +- [ColumnMin.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-min\src\main\java\io\datavines\metric\plugin\ColumnMin.java) +- [ColumnMax.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-max\src\main\java\io\datavines\metric\plugin\ColumnMax.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) + +**本节来源** +- [ColumnMin.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-min\src\main\java\io\datavines\metric\plugin\ColumnMin.java#L31-L87) +- [ColumnMax.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-max\src\main\java\io\datavines\metric\plugin\ColumnMax.java#L31-L88) + +## SQL生成策略 + +系统的SQL生成策略采用了一种高度抽象和可扩展的设计模式。核心思想是将SQL的生成逻辑从具体的业务规则中解耦,通过 `MetricScript` 接口来定义各种SQL片段的模板。 + +**核心组件**: +- **SqlMetric 接口**:定义了所有度量规则的通用行为,如获取实际值、获取无效项、验证配置等。 +- **MetricScript 接口**:定义了所有SQL片段的生成方法,如 `minActualValue`、`maxActualValue`、`columnGteMin` 等。这些方法返回带有占位符(如 `${column}`, `${min}`, `${max}`)的SQL模板字符串。 +- **具体实现**:针对不同的数据库(如MySQL、Oracle、PostgreSQL),通过SPI机制加载对应的 `MetricScript` 实现类(如 `MysqlMetricScript`、`OracleMetricScript`),以适应不同数据库的语法差异。 + +**生成流程**: +1. 业务规则(如 `ColumnValueBetween`)在 `prepare` 阶段根据配置决定需要哪些SQL片段。 +2. 通过 `ConnectorFactory` 获取当前数据源对应的 `MetricScript` 实例。 +3. 调用 `MetricScript` 的相应方法(如 `columnGteMin()`)获取SQL模板。 +4. 将模板中的占位符替换为实际的表名、列名和配置值,最终生成可执行的SQL语句。 + +```mermaid +flowchart TD +A[业务规则] --> B{配置检查} +B --> |配置了min| C[调用columnGteMin()] +B --> |配置了max| D[调用columnLteMax()] +C --> E[获取SQL模板] +D --> E +E --> F[替换占位符] +F --> G[生成最终SQL] +G --> H[执行SQL] +H --> I[返回结果] +``` + +**流程图来源** +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java) + +**本节来源** +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L21-L160) + +## 数据类型兼容性 + +系统对不同数据类型的范围检查进行了明确的兼容性设计,以确保检查的准确性和有效性。 + +| 规则名称 | 支持的数据类型 | 说明 | +| :--- | :--- | :--- | +| **ColumnValueBetween** | 数值型、字符串型、日期时间型 | 可以检查数值范围、字符串字典序范围或日期时间范围。 | +| **ColumnMin** | 仅数值型 | 仅对数值型数据计算最小值,避免对字符串进行无意义的比较。 | +| **ColumnMax** | 仅数值型 | 仅对数值型数据计算最大值,确保结果的可解释性。 | + +**边界条件处理**: +- **空值处理**:当检查的列包含 `NULL` 值时,`ColumnValueBetween` 规则默认会将 `NULL` 值视为不满足范围条件(因为 `NULL` 与任何值的比较结果都是 `UNKNOWN`)。如果需要特殊处理,可以通过配置或自定义规则来实现。 +- **类型转换**:在进行比较时,系统依赖于底层数据库的隐式类型转换。例如,将字符串 `"123"` 与数字 `123` 进行比较时,数据库会尝试将其转换为相同类型。为避免意外,建议确保配置的 `min`/`max` 值与列的数据类型保持一致。 + +**本节来源** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L79-L81) +- [ColumnMin.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-min\src\main\java\io\datavines\metric\plugin\ColumnMin.java#L84-L86) +- [ColumnMax.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-max\src\main\java\io\datavines\metric\plugin\ColumnMax.java#L84-L86) + +## 业务应用场景 + +### 金融场景 + +在金融领域,数值范围检查对于确保交易数据的准确性至关重要。 +- **交易金额检查**:使用 `ColumnValueBetween` 规则检查 `transaction_amount` 列,确保所有交易金额在合理的范围内(如 0.01 元到 100 万元),防止因系统错误或欺诈行为导致的异常大额或负数交易。 +- **账户余额监控**:使用 `ColumnMin` 规则定期检查 `account_balance` 列的最小值,确保没有账户余额为负数(除非是透支账户),及时发现潜在的财务风险。 + +### 电商场景 + +在电商平台,数值范围检查有助于维护商品和订单数据的完整性。 +- **商品价格验证**:使用 `ColumnValueBetween` 规则检查 `product_price` 列,确保价格在 0.01 元到 10 万元之间,防止因录入错误导致的天价商品或免费商品。 +- **库存数量监控**:使用 `ColumnMax` 规则检查 `stock_quantity` 列的最大值,识别库存异常高的商品,这可能意味着数据同步错误或需要进行库存盘点。 + +**本节来源** +- 本节内容基于对规则功能的理解和行业最佳实践的推断,未直接引用具体代码文件。 + +## 性能优化建议 + +### 高基数列的处理 + +对于基数(Cardinality)非常高的列(如用户ID、订单号),直接进行范围检查可能会导致全表扫描,影响性能。 +- **索引优化**:确保被检查的列上建立了适当的数据库索引(如B-Tree索引),可以显著加速 `WHERE` 条件的过滤过程。 +- **分区表查询**:如果数据表按时间或其他维度进行了分区,应尽量在查询中包含分区键,以利用分区裁剪(Partition Pruning)技术,减少需要扫描的数据量。 +- **采样检查**:对于非关键性检查,可以考虑对数据进行随机采样,只检查样本数据的范围,以牺牲一定的准确性来换取性能的提升。 + +**本节来源** +- 本节内容基于数据库性能优化的一般原则,未直接引用具体代码文件。 + +## 动态阈值配置 + +系统支持通过配置文件或API动态设置 `min` 和 `max` 阈值,无需修改代码即可调整检查规则。 +- **配置方式**:可以在任务配置中直接指定 `min` 和 `max` 的值。例如,`{"column": "age", "min": "18", "max": "100"}`。 +- **外部化配置**:可以将阈值存储在外部配置中心(如ZooKeeper、Consul),规则在执行时动态拉取最新的阈值,实现真正的动态调整。 + +**本节来源** +- [ColumnValueBetween.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-value-between\src\main\java\io\datavines\metric\plugin\ColumnValueBetween.java#L35-L36) + +## 时间序列数据处理 + +虽然 `ColumnMin` 和 `ColumnMax` 规则本身不直接处理时间序列,但可以与时间维度结合使用。 +- **趋势分析**:可以按天、周、月等时间粒度分别计算某个指标(如销售额)的 `ColumnMax`,然后分析其随时间的变化趋势,识别增长或下降的模式。 +- **动态基准**:可以将过去一段时间(如过去30天)的 `ColumnMax` 值作为当前检查的动态上限,实现自适应的异常检测。 + +**本节来源** +- 本节内容基于对规则功能的扩展应用,未直接引用具体代码文件。 + +## 结论 + +本文档详细介绍了 `ColumnValueBetween`、`ColumnMin` 和 `ColumnMax` 三种数值范围检查规则的业务应用和实现细节。系统通过抽象的 `MetricScript` 接口实现了灵活的SQL生成策略,支持多种数据类型,并在金融、电商等场景下具有广泛的应用价值。通过合理的索引和分区策略,可以有效优化高基数列的检查性能。未来可以进一步探索与机器学习模型结合,实现更智能的动态阈值设定。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\347\273\237\350\256\241\346\214\207\346\240\207\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\347\273\237\350\256\241\346\214\207\346\240\207\346\243\200\346\237\245.md" new file mode 100644 index 00000000..043b83df --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\347\273\237\350\256\241\346\214\207\346\240\207\346\243\200\346\237\245.md" @@ -0,0 +1,189 @@ +# 统计指标检查 + + +**本文档引用文件** +- [ColumnAvg.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-avg/src/main/java/io/datavines/metric/plugin/ColumnAvg.java) +- [ColumnSum.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-sum/src/main/java/io/datavines/metric/plugin/ColumnSum.java) +- [ColumnStdDev.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-std-dev/src/main/java/io/datavines/metric/plugin/ColumnStdDev.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java) +- [ColumnInfo.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ColumnInfo.java) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) + + +## 目录 +1. [引言](#引言) +2. [核心统计规则解析](#核心统计规则解析) +3. [数据质量监控中的应用](#数据质量监控中的应用) +4. [计算优化与执行策略](#计算优化与执行策略) +5. [行业应用案例](#行业应用案例) +6. [性能调优指南](#性能调优指南) +7. [结论](#结论) + +## 引言 +本文档全面解析DataVines平台中ColumnAvg、ColumnSum和ColumnStdDev等核心统计指标检查规则的实现机制与应用场景。这些规则作为数据质量监控体系的重要组成部分,通过量化分析手段保障数据的完整性、一致性与可靠性。文档深入剖析其计算逻辑、适用场景及系统集成方式,为开发者和数据工程师提供详尽的技术参考。 + +## 核心统计规则解析 + +### ColumnAvg(平均值检查) +`ColumnAvg`类实现了对指定数值型列的平均值计算功能,继承自`BaseSingleTableColumn`基类并实现`SqlMetric`接口。该规则通过调用连接器工厂生成特定数据库方言的AVG聚合SQL语句,在执行时可附加过滤条件以支持条件平均值计算。其维度归类为“完整性”,仅适用于`NUMERIC_TYPE`数据类型。 + +**统计逻辑**: +使用标准SQL `AVG()`函数计算列值的算术平均数,自动忽略NULL值。结果通过`getActualValue`方法返回封装后的`ExecuteSql`对象,包含唯一键标识和目标结果表名。 + +**Section sources** +- [ColumnAvg.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-avg/src/main/java/io/datavines/metric/plugin/ColumnAvg.java#L33-L92) + +### ColumnSum(总值检查) +`ColumnSum`类用于计算指定数值列的总和,同样实现`SqlMetric`接口并遵循单表列级指标规范。其核心逻辑调用底层连接器的`sumActualValue`方法生成SUM聚合SQL,支持动态过滤条件拼接,确保计算过程可追溯且可配置。 + +**统计逻辑**: +采用SQL `SUM()`聚合函数对非空数值进行累加。与`ColumnAvg`类似,通过`METRIC_UNIQUE_KEY`保证任务执行的唯一性,并将中间结果写入临时结果表以便后续验证与比对。 + +**Section sources** +- [ColumnSum.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-sum/src/main/java/io/datavines/metric/plugin/ColumnSum.java#L31-L88) + +### ColumnStdDev(标准差检查) +`ColumnStdDev`类提供列值离散程度的度量能力,反映数据分布的波动性。其实现依赖于数据库内置的标准差函数(如STDDEV或STDDEV_SAMP),通过`getActualValue`构造专用SQL完成计算。 + +**统计逻辑**: +利用SQL标准差函数评估数据集相对于均值的偏离程度。高标准差表明数据分布分散,可能提示异常值或数据质量问题;低标准差则表示数据集中稳定。此指标在金融风控、质量检测等领域具有重要价值。 + +**Section sources** +- [ColumnStdDev.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-std-dev/src/main/java/io/datavines/metric/plugin/ColumnStdDev.java#L31-L88) + +### 接口契约与配置体系 +所有统计规则均实现`SqlMetric`接口,统一定义了名称获取、维度分类、SQL生成、参数校验等核心方法。`MetricConstants`中预定义了结果表结构(`RESULT_COLUMN_LIST`),确保各指标输出格式一致,便于统一存储与分析。 + +```mermaid +classDiagram +class SqlMetric { +<> ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++getActualValue(Map) ExecuteSql ++getInvalidateItems(Map) ExecuteSql ++validateConfig(Map) CheckResult ++getConfigMap() Map ++prepare(Map) void +} +class ColumnAvg { ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++getActualValue(Map) ExecuteSql +} +class ColumnSum { ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++getActualValue(Map) ExecuteSql +} +class ColumnStdDev { ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++getActualValue(Map) ExecuteSql +} +SqlMetric <|-- ColumnAvg +SqlMetric <|-- ColumnSum +SqlMetric <|-- ColumnStdDev +ColumnAvg --> BaseSingleTableColumn : "extends" +ColumnSum --> BaseSingleTableColumn : "extends" +ColumnStdDev --> BaseSingleTableColumn : "extends" +``` + +**Diagram sources** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L29-L112) +- [ColumnAvg.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-avg/src/main/java/io/datavines/metric/plugin/ColumnAvg.java#L33-L92) +- [ColumnSum.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-sum/src/main/java/io/datavines/metric/plugin/ColumnSum.java#L31-L88) +- [ColumnStdDev.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-std-dev/src/main/java/io/datavines/metric/plugin/ColumnStdDev.java#L31-L88) + +## 数据质量监控中的应用 + +### 均值异常检测 +通过定期执行`ColumnAvg`检查,建立关键业务指标(如订单金额、用户活跃时长)的历史均值基线。结合预期值插件(如`daily-avg`或`weekly-avg`),系统可自动识别显著偏离正常范围的数据波动,及时触发告警。 + +**应用场景**:电商平台监控日均交易额,防止因系统故障或刷单行为导致的数据异常。 + +### 总量核对 +`ColumnSum`广泛应用于财务对账、库存盘点等强一致性场景。通过对交易流水、库存变动等字段求和,并与外部系统或历史累计值比对,可快速发现数据丢失或重复记录问题。 + +**应用场景**:银行每日核对总交易额,确保账务系统数据完整无误。 + +### 离散程度评估 +`ColumnStdDev`帮助识别数据分布的稳定性。在数据接入初期,若某字段标准差突然增大,可能意味着数据源格式变更或采集逻辑错误;长期跟踪标准差趋势还可辅助发现潜在的数据漂移问题。 + +**应用场景**:物联网平台监控传感器读数的标准差,判断设备运行状态是否正常。 + +```mermaid +flowchart TD +A[数据表] --> B{选择统计规则} +B --> C[ColumnAvg] +B --> D[ColumnSum] +B --> E[ColumnStdDev] +C --> F[计算平均值] +D --> G[计算总和] +E --> H[计算标准差] +F --> I[与预期值比较] +G --> I +H --> I +I --> J{是否满足阈值?} +J --> |否| K[触发告警] +J --> |是| L[记录质量报告] +``` + +**Diagram sources** +- [ColumnAvg.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-avg/src/main/java/io/datavines/metric/plugin/ColumnAvg.java#L72-L85) +- [ColumnSum.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-sum/src/main/java/io/datavines/metric/plugin/ColumnSum.java#L68-L81) +- [ColumnStdDev.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-std-dev/src/main/java/io/datavines/metric/plugin/ColumnStdDev.java#L68-L81) + +## 计算优化与执行策略 + +### 浮点数精度处理 +系统通过数据库原生聚合函数执行计算,精度由底层存储引擎保障。建议在配置阶段明确字段的数据类型与精度要求,避免因类型转换引发精度损失。对于高精度计算需求,可结合`DECIMAL`类型字段使用。 + +### 大数据量下的计算优化 +- **过滤下推**:在`getActualValue`中支持`filters`条件拼接,将WHERE子句直接嵌入聚合SQL,减少扫描数据量。 +- **索引利用**:确保被检查列已建立适当索引,尤其对于频繁查询的高基数列。 +- **分区剪枝**:当表按时间或其他维度分区时,SQL生成器应自动利用分区信息缩小扫描范围。 + +### 分布式环境中的执行策略 +在Spark或Flink等分布式引擎中执行时,`EngineExecutor`将SQL任务提交至集群,利用并行计算能力加速大规模数据处理。通过`Livy`或`Yarn`调度平台实现资源隔离与任务监控,确保高并发场景下的稳定性。 + +**Section sources** +- [BaseSingleTableColumn.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-base/src/main/java/io/datavines/metric/plugin/base/BaseSingleTableColumn.java) +- [EngineExecutor.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) + +## 行业应用案例 + +### 金融行业:交易数据完整性验证 +某银行使用`ColumnSum`规则每日核对核心交易系统的总交易额,与清算系统进行交叉验证。一旦发现差异超过0.1%,立即启动异常排查流程,有效防止了因数据同步延迟导致的账务不平问题。 + +### 电商行业:用户行为分析质量保障 +电商平台采用`ColumnAvg`监控用户日均停留时长,结合`ColumnStdDev`分析用户行为离散度。当标准差异常升高时,提示可能存在爬虫流量或A/B测试配置错误,保障分析结果的准确性。 + +### 制造业:设备传感器数据监控 +工厂物联网系统利用`ColumnStdDev`持续监测关键设备的温度、振动等传感器读数。当标准差超过预设阈值时,表明设备运行状态不稳定,系统自动通知运维人员进行检查,实现预测性维护。 + +## 性能调优指南 + +### SQL生成优化 +- 避免在`filters`中使用复杂表达式或函数,影响执行计划生成。 +- 对于超大表,建议配合采样策略(如`TABLESAMPLE`)进行近似计算,平衡精度与性能。 + +### 资源配置建议 +- 在`datavines-engine-config`中合理设置执行超时时间与内存限制。 +- 对于高频检查任务,采用异步执行模式,避免阻塞主线程。 + +### 监控与诊断 +- 启用SQL执行日志,分析慢查询并优化执行计划。 +- 利用`JobExecutionLog`跟踪任务执行耗时,识别性能瓶颈。 + +## 结论 +`ColumnAvg`、`ColumnSum`和`ColumnStdDev`作为DataVines平台的基础统计指标,为数据质量监控提供了强有力的量化工具。通过标准化接口设计与灵活的执行框架,这些规则能够高效集成至各类数据环境中,支撑起从基础校验到深度分析的多层次质量保障体系。未来可进一步扩展支持加权平均、分位数等高级统计函数,提升系统的分析能力。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\351\235\236\347\251\272_\347\251\272\345\200\274\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\351\235\236\347\251\272_\347\251\272\345\200\274\346\243\200\346\237\245.md" new file mode 100644 index 00000000..f65ca518 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\345\215\225\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\351\235\236\347\251\272_\347\251\272\345\200\274\346\243\200\346\237\245.md" @@ -0,0 +1,216 @@ +# 非空/空值检查 + + +**本文档引用的文件** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-null\src\main\java\io\datavines\metric\plugin\ColumnNull.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [JdbcMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcMetricScript.java) + + +## 目录 +1. [介绍](#介绍) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 介绍 +DataVines是一个数据质量监控系统,提供多种数据质量检查规则。其中,非空/空值检查是数据完整性验证的重要组成部分。本文档详细分析了`ColumnNotNull`和`ColumnNull`两个核心规则的实现原理、业务场景、SQL生成逻辑和执行流程。这两个规则分别用于检查数据库列中是否存在非空值和空值,是确保数据完整性和有效性的基础工具。 + +## 核心组件 +`ColumnNotNull`和`ColumnNull`是DataVines中实现非空和空值检查的核心组件。它们都继承自`BaseSingleTableColumnNotUseView`基类,实现了`SqlMetric`接口。这两个组件通过生成相应的SQL查询来检查指定列的空值或非空值情况,并返回检查结果。它们的主要区别在于检查的条件相反:`ColumnNotNull`检查列中非空值的数量,而`ColumnNull`检查列中空值的数量。 + +**组件来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-null\src\main\java\io\datavines\metric\plugin\ColumnNull.java) + +## 架构概述 +非空/空值检查规则的架构基于插件化设计模式,通过继承基类和实现接口来提供一致的API。整个架构分为三层:接口层、基类层和具体实现层。接口层定义了所有度量规则的通用行为,基类层提供了通用的功能实现,而具体实现层则针对特定的检查需求进行定制化开发。 + +```mermaid +graph TD +SqlMetric[SqlMetric接口] --> BaseSingleTable[BaseSingleTable基类] +BaseSingleTable --> BaseSingleTableColumnNotUseView[BaseSingleTableColumnNotUseView基类] +BaseSingleTableColumnNotUseView --> ColumnNotNull[ColumnNotNull实现] +BaseSingleTableColumnNotUseView --> ColumnNull[ColumnNull实现] +MetricScript[MetricScript接口] --> JdbcMetricScript[JdbcMetricScript实现] +JdbcMetricScript --> MysqlMetricScript[MySQL特定实现] +JdbcMetricScript --> PostgreSqlMetricScript[PostgreSQL特定实现] +``` + +**图表来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) + +## 详细组件分析 + +### ColumnNotNull和ColumnNull分析 +`ColumnNotNull`和`ColumnNull`是两个对称的检查规则,分别用于验证数据列中的非空值和空值。它们的实现结构相似,都通过继承`BaseSingleTableColumnNotUseView`基类来获得基本功能,并重写特定方法来实现各自的业务逻辑。 + +#### 类图分析 +```mermaid +classDiagram +class SqlMetric { +<> ++String getName() ++String getZhName() ++MetricDimension getDimension() ++MetricType getType() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getInvalidateItems(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) ++Map~String,ConfigItem~ getConfigMap() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class BaseSingleTable { ++Map~String,ConfigItem~ configMap ++String[] requiredOptions ++ConnectorFactory getConnectorFactory(Map~String,String~) ++void prepare(Map~String,String~) ++ExecuteSql getActualValue(Map~String,String~) +} +class BaseSingleTableColumnNotUseView { ++MetricLevel getLevel() ++boolean isInvalidateItemsCanOutput() ++ExecuteSql getDirectActualValue(Map~String,String~) +} +class ColumnNotNull { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() +} +class ColumnNull { ++String getName() ++String getZhName() ++MetricDimension getDimension() ++void prepare(Map~String,String~) ++DataVinesDataType[] suitableType() ++MetricDirectionType getDirectionType() +} +SqlMetric <|-- BaseSingleTable +BaseSingleTable <|-- BaseSingleTableColumnNotUseView +BaseSingleTableColumnNotUseView <|-- ColumnNotNull +BaseSingleTableColumnNotUseView <|-- ColumnNull +``` + +**图表来源** +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-null\src\main\java\io\datavines\metric\plugin\ColumnNull.java) + +#### 执行流程分析 +非空/空值检查的执行流程遵循标准的数据质量检查模式,从配置准备到SQL生成再到结果返回。`ColumnNotNull`和`ColumnNull`的执行流程相似,主要区别在于生成的SQL条件不同。 + +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant ColumnNotNull as ColumnNotNull +participant BaseSingleTable as BaseSingleTable +participant ConnectorFactory as ConnectorFactory +participant MetricScript as MetricScript +用户->>ColumnNotNull : 调用prepare(config) +ColumnNotNull->>ColumnNotNull : 验证配置包含"column" +ColumnNotNull->>ConnectorFactory : getConnectorFactory(config) +ConnectorFactory-->>ColumnNotNull : 返回连接器工厂 +ColumnNotNull->>MetricScript : columnNotNull()/columnIsNull() +MetricScript-->>ColumnNotNull : 返回SQL条件 +ColumnNotNull->>BaseSingleTable : super.prepare(config) +BaseSingleTable->>BaseSingleTable : 构建完整SQL查询 +BaseSingleTable-->>ColumnNotNull : 完成准备 +ColumnNotNull->>用户 : 返回准备完成状态 +用户->>ColumnNotNull : 调用getActualValue() +ColumnNotNull->>BaseSingleTable : getActualValue() +BaseSingleTable-->>用户 : 返回执行SQL +``` + +**图表来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-null\src\main\java\io\datavines\metric\plugin\ColumnNull.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) + +#### SQL生成逻辑分析 +非空/空值检查的核心在于SQL条件的生成。`MetricScript`接口提供了`columnNotNull()`和`columnIsNull()`两个默认方法,用于生成相应的SQL条件。这些方法使用模板字符串,通过替换`${column}`占位符来生成具体的SQL条件。 + +```mermaid +flowchart TD +Start([开始]) --> CheckType{"检查类型?"} +CheckType --> |非空检查| GenerateNotNull["生成: ${column} is not null"] +CheckType --> |空值检查| GenerateNull["生成: (${column} is null)"] +GenerateNotNull --> ReplacePlaceholder["替换${column}为实际列名"] +GenerateNull --> ReplacePlaceholder +ReplacePlaceholder --> ReturnSQL["返回生成的SQL条件"] +ReturnSQL --> End([结束]) +``` + +**图表来源** +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) + +## 依赖分析 +非空/空值检查规则依赖于多个核心组件和接口,形成了一个完整的依赖链。主要依赖包括`SqlMetric`接口、`BaseSingleTable`基类、`BaseSingleTableColumnNotUseView`基类以及`MetricScript`接口。 + +```mermaid +graph TD +ColumnNotNull --> BaseSingleTableColumnNotUseView +ColumnNull --> BaseSingleTableColumnNotUseView +BaseSingleTableColumnNotUseView --> BaseSingleTable +BaseSingleTable --> SqlMetric +ColumnNotNull --> MetricScript +ColumnNull --> MetricScript +BaseSingleTable --> ConnectorFactory +ConnectorFactory --> MetricScript +``` + +**图表来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-null\src\main\java\io\datavines\metric\plugin\ColumnNull.java) +- [BaseSingleTableColumnNotUseView.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTableColumnNotUseView.java) +- [BaseSingleTable.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-base\src\main\java\io\datavines\metric\plugin\base\BaseSingleTable.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) + +## 性能考虑 +在使用非空/空值检查规则时,需要考虑以下性能因素: + +1. **索引利用**:对于大表的空值检查,如果被检查的列上有索引,查询性能会显著提高。数据库优化器可以利用索引快速定位空值或非空值记录。 + +2. **数据量影响**:随着表中数据量的增加,COUNT查询的执行时间也会相应增加。对于超大表,建议在非高峰时段执行此类检查。 + +3. **并发控制**:在高并发环境下执行大量数据质量检查可能会影响数据库的整体性能,需要合理安排检查任务的执行时间。 + +4. **缓存策略**:对于频繁执行的检查任务,可以考虑实现结果缓存机制,避免重复执行相同的查询。 + +5. **分区表优化**:对于分区表,可以针对特定分区执行检查,而不是扫描整个表,从而提高查询效率。 + +## 故障排除指南 +在使用非空/空值检查规则时,可能会遇到以下常见问题及解决方案: + +1. **配置错误**:确保配置中包含必需的"column"参数。缺少此参数会导致检查无法执行。 + +2. **列名不存在**:检查指定的列名是否存在于目标表中,列名区分大小写,需要确保完全匹配。 + +3. **权限不足**:确保执行检查的数据库用户具有查询目标表的权限。 + +4. **连接问题**:检查数据库连接配置是否正确,包括主机名、端口、用户名和密码。 + +5. **性能问题**:如果检查执行时间过长,考虑在被检查的列上创建索引,或在数据量较小的时间段执行检查。 + +6. **结果不准确**:确认数据库的空值定义是否与检查规则一致,某些数据库可能对空字符串和NULL值有不同的处理方式。 + +**组件来源** +- [ColumnNotNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-not-null\src\main\java\io\datavines\metric\plugin\ColumnNotNull.java) +- [ColumnNull.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-column-null\src\main\java\io\datavines\metric\plugin\ColumnNull.java) + +## 结论 +`ColumnNotNull`和`ColumnNull`是非空/空值检查的核心实现,通过继承基类和实现接口的方式提供了灵活而强大的数据质量检查功能。这两个规则利用模板化的SQL生成机制,能够适应不同的数据库类型和配置需求。其设计遵循了良好的面向对象原则,具有高内聚、低耦合的特点,便于维护和扩展。通过合理使用这些规则,可以有效保证数据的完整性和有效性,为数据驱动的业务决策提供可靠的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\207\252\345\256\232\344\271\211SQL\346\243\200\346\237\245\350\247\204\345\210\231.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\207\252\345\256\232\344\271\211SQL\346\243\200\346\237\245\350\247\204\345\210\231.md" new file mode 100644 index 00000000..d3752e77 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\207\252\345\256\232\344\271\211SQL\346\243\200\346\237\245\350\247\204\345\210\231.md" @@ -0,0 +1,236 @@ +# 自定义SQL检查规则 + + +**本文档引用的文件** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [ExecuteSql.java](file://datavines-common\src\main\java\io\datavines\common\entity\ExecuteSql.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [ConfigItem.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ConfigItem.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件分析](#核心组件分析) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 简介 +本文档详细介绍了DataVines数据质量检查框架中的自定义聚合SQL检查规则的实现机制。该规则允许用户通过编写自定义的聚合SQL语句来实现灵活的数据质量验证,适用于各种复杂的业务场景。文档将深入分析CustomAggregateSql规则的实现原理、参数配置、执行流程以及最佳实践。 + +## 核心组件分析 + +自定义SQL检查规则的核心实现位于`CustomAggregateSql`类中,该类实现了`SqlMetric`接口,提供了灵活的数据质量检查能力。通过分析代码结构,可以理解其如何将用户定义的SQL语句集成到数据质量检查流程中。 + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) + +## 架构概述 + +```mermaid +graph TD +subgraph "数据质量检查引擎" +JobConfig[作业配置] +MetricEngine[指标引擎] +SqlExecutor[SQL执行器] +ResultValidator[结果验证器] +end +subgraph "自定义SQL检查" +UserInput[用户输入] +CustomSql[自定义聚合SQL] +ParameterSubstitution[参数替换] +ExecuteSql[执行SQL] +end +JobConfig --> MetricEngine +UserInput --> CustomSql +CustomSql --> ParameterSubstitution +ParameterSubstitution --> ExecuteSql +ExecuteSql --> SqlExecutor +SqlExecutor --> ResultValidator +MetricEngine --> ResultValidator +``` + +**图表来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) + +## 详细组件分析 + +### CustomAggregateSql类分析 + +#### 类图 +```mermaid +classDiagram +class SqlMetric { +<> ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++validateConfig(config) CheckResult ++getConfigMap() Map~String,ConfigItem~ ++getActualValue(inputParameter) ExecuteSql ++isCustomSql() boolean +} +class CustomAggregateSql { +-requiredOptions Set~String~ +-configMap HashMap~String,ConfigItem~ ++CustomAggregateSql() ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++validateConfig(config) CheckResult ++getConfigMap() Map~String,ConfigItem~ ++getActualValue(inputParameter) ExecuteSql ++isCustomSql() boolean +} +class ConfigItem { +-esLabel String +-zhLabel String +-key String ++getKey() String ++getLabel(isEn) String +} +class ExecuteSql { +-sql String +-resultTable String +-isErrorOutput boolean ++ExecuteSql(sql, resultTable) +} +CustomAggregateSql ..|> SqlMetric : 实现 +CustomAggregateSql --> ConfigItem : 包含 +CustomAggregateSql --> ExecuteSql : 返回 +``` + +**图表来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [ConfigItem.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ConfigItem.java) +- [ExecuteSql.java](file://datavines-common\src\main\java\io\datavines\common\entity\ExecuteSql.java) + +#### 执行流程分析 + +```mermaid +sequenceDiagram +participant 用户 as 用户界面 +participant 配置引擎 as 配置引擎 +participant CustomAggregateSql as CustomAggregateSql +participant SQL执行器 as SQL执行器 +participant 结果验证 as 结果验证器 +用户->>配置引擎 : 提交自定义SQL检查配置 +配置引擎->>CustomAggregateSql : 初始化配置参数 +CustomAggregateSql->>CustomAggregateSql : 验证配置有效性 +CustomAggregateSql-->>配置引擎 : 返回验证结果 +配置引擎->>CustomAggregateSql : 调用getActualValue() +CustomAggregateSql->>CustomAggregateSql : 处理SQL语句 +CustomAggregateSql->>CustomAggregateSql : 替换actual_value别名 +CustomAggregateSql-->>配置引擎 : 返回ExecuteSql对象 +配置引擎->>SQL执行器 : 执行SQL查询 +SQL执行器-->>结果验证 : 返回实际值 +结果验证->>结果验证 : 与预期值比较 +结果验证-->>用户 : 显示检查结果 +``` + +**图表来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) + +#### 配置参数处理流程 + +```mermaid +flowchart TD +Start([开始]) --> Initialize["初始化配置参数"] +Initialize --> Validate["验证必填参数"] +Validate --> IsValid{"参数有效?"} +IsValid --> |否| ReturnError["返回错误信息"] +IsValid --> |是| ProcessSQL["处理自定义SQL"] +ProcessSQL --> CheckAlias["检查actual_value别名"] +CheckAlias --> HasAlias{"包含别名?"} +HasAlias --> |是| ReplaceAlias["替换别名为actual_value_唯一键"] +HasAlias --> |否| KeepOriginal["保持原SQL"] +ReplaceAlias --> GenerateExecuteSql["生成ExecuteSql对象"] +KeepOriginal --> GenerateExecuteSql +GenerateExecuteSql --> ReturnResult["返回ExecuteSql"] +ReturnError --> End([结束]) +ReturnResult --> End +``` + +**图表来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [ExecuteSql.java](file://datavines-common\src\main\java\io\datavines\common\entity\ExecuteSql.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) + +## 依赖分析 + +```mermaid +graph TD +CustomAggregateSql --> SqlMetric : 实现接口 +CustomAggregateSql --> ConfigItem : 使用配置项 +CustomAggregateSql --> ExecuteSql : 返回执行SQL +CustomAggregateSql --> ConfigChecker : 验证配置 +CustomAggregateSql --> StringUtils : 字符串处理 +BaseJobConfigurationBuilder --> CustomAggregateSql : 调用getActualValue +BaseJobConfigurationBuilder --> MetricParserUtils : 设置转换配置 +MetricParserUtils --> PluginLoader : 加载插件 +MetricParserUtils --> ParameterUtils : 参数替换 +ExpectedValue --> PluginLoader : 加载预期值插件 +style CustomAggregateSql fill:#f9f,stroke:#333 +style SqlMetric fill:#bbf,stroke:#333,color:#fff +style ConfigItem fill:#f96,stroke:#333 +style ExecuteSql fill:#6f9,stroke:#333 +``` + +**图表来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) + +## 性能考虑 + +自定义SQL检查规则在设计时考虑了性能优化,通过以下机制确保高效执行: + +1. **参数化查询**:使用参数占位符避免SQL注入,同时提高查询计划缓存效率 +2. **唯一键处理**:为每个检查实例生成唯一键,避免并发执行时的命名冲突 +3. **配置验证**:在执行前验证必填参数,减少无效执行 +4. **结果表管理**:明确指定结果表名称,便于后续处理和清理 + +虽然自定义SQL提供了极大的灵活性,但用户应注意编写高效的SQL语句,避免全表扫描和复杂的连接操作,特别是在处理大规模数据集时。 + +## 故障排除指南 + +当自定义SQL检查规则出现问题时,可参考以下排查步骤: + +1. **检查配置参数**:确保"actual_aggregate_sql"参数已正确配置 +2. **验证SQL语法**:在目标数据库中测试SQL语句的正确性 +3. **检查表名引用**:确认SQL中的表名与配置一致 +4. **查看日志信息**:检查执行日志中的错误详情 +5. **验证权限**:确保执行账户有足够权限访问相关表 + +**本节来源** +- [CustomAggregateSql.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-custom-aggregate-sql\src\main\java\io\datavines\metric\plugin\CustomAggregateSql.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) + +## 结论 + +自定义聚合SQL检查规则为DataVines框架提供了强大的灵活性,使用户能够根据特定业务需求创建复杂的数据质量检查。通过`CustomAggregateSql`类的实现,系统能够安全地执行用户定义的SQL语句,并将其集成到标准的数据质量检查流程中。该功能特别适用于需要复杂聚合逻辑、跨表关联分析或特定业务规则验证的场景,极大地扩展了数据质量检查的能力范围。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\344\270\244\350\241\250\345\200\274\346\257\224\350\276\203\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\344\270\244\350\241\250\345\200\274\346\257\224\350\276\203\346\243\200\346\237\245.md" new file mode 100644 index 00000000..1b0a1f4b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\344\270\244\350\241\250\345\200\274\346\257\224\350\276\203\346\243\200\346\237\245.md" @@ -0,0 +1,182 @@ +# 两表值比较检查 + + +**本文档引用的文件** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java) +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [CommonConstants.java](file://datavines-common\src\main\java\io\datavines\common\CommonConstants.java) +- [MetricConstants.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\MetricConstants.java) + + +## 目录 +1. [介绍](#介绍) +2. [配置参数](#配置参数) +3. [执行逻辑与数据验证流程](#执行逻辑与数据验证流程) +4. [实际使用案例](#实际使用案例) +5. [常见问题解决方案](#常见问题解决方案) + +## 介绍 + +两表值比较检查是一种用于验证两个数据表中特定字段数值一致性的数据质量检查方法。该功能主要用于数据迁移、数据同步或数据一致性验证等业务场景,通过比较源表和目标表中对应字段的数值差异,确保数据的准确性和完整性。 + +该功能属于DataVines数据质量框架中的多表值比较模块,其核心实现类为`MultiTableValueComparison`,该类实现了`SqlMetric`接口,提供了两表值比较的完整功能。该检查方法属于准确性(ACCURACY)维度,其指标类型为`MULTI_TABLE_VALUE_COMPARISON`。 + +**本节来源** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java#L31-L51) + +## 配置参数 + +两表值比较检查涉及多个关键配置参数,这些参数定义了比较的源表、目标表、比较字段、比较运算符和阈值等。以下是主要配置参数的详细说明: + +- **源表配置**: + - `table`: 源表名称 + - `datasource_id`: 源数据源ID + - `column`: 源表比较字段 + - `actual_execute_sql`: 源表实际值查询SQL + +- **目标表配置**: + - `table2`: 目标表名称 + - `database2`: 目标数据库名称 + - `target_datasource_id`: 目标数据源ID + - `target_column`: 目标表比较字段 + - `expected_execute_sql`: 目标表期望值查询SQL + +- **比较规则配置**: + - `operator`: 比较运算符,如等于(=)、大于(>)、小于(<)等 + - `threshold`: 阈值,用于定义可接受的差异范围 + - `result_formula`: 结果计算公式,定义如何计算比较结果 + - `mappingColumns`: 映射字段,用于连接两个表的关联字段 + +- **其他配置**: + - `metric_unique_key`: 指标唯一键,用于标识特定的检查实例 + - `failure_strategy`: 失败策略,定义检查失败时的处理方式 + - `filter`: 源表过滤条件 + - `target_filter`: 目标表过滤条件 + +这些配置参数通过`ConfigConstants`和`CommonConstants`类中的常量定义,确保了配置的一致性和可维护性。 + +**本节来源** +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java#L24-L54) +- [CommonConstants.java](file://datavines-common\src\main\java\io\datavines\common\CommonConstants.java#L177-L182) + +## 执行逻辑与数据验证流程 + +两表值比较检查的执行逻辑主要由`MultiTableValueComparison`类和`LocalMultiTableValueComparisonMetricBuilder`类协同完成。整个流程可以分为配置构建、SQL生成、执行和结果验证四个阶段。 + +### 配置构建阶段 + +`LocalMultiTableValueComparisonMetricBuilder`类负责构建两表值比较所需的配置。该类继承自`BaseLocalConfigurationBuilder`,通过`buildTransformConfigs`方法构建转换配置。在构建过程中,系统会获取指标的唯一键,并从插件加载器中加载相应的`SqlMetric`实现。 + +```mermaid +flowchart TD +Start([开始]) --> BuildConfig["构建配置参数"] +BuildConfig --> GetMetricKey["获取指标唯一键"] +GetMetricKey --> LoadPlugin["加载SqlMetric插件"] +LoadPlugin --> SetInputParam["设置输入参数"] +SetInputParam --> BuildActualSql["构建实际值SQL"] +BuildActualSql --> BuildExpectedSql["构建期望值SQL"] +BuildExpectedSql --> End([配置构建完成]) +``` + +**图表来源** +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L48-L84) + +### SQL生成与执行阶段 + +在配置构建完成后,系统会生成用于获取实际值和期望值的SQL语句。`getActualValueExecuteSql`方法负责生成源表的查询SQL,而`getExceptedValueExecuteSql`方法负责生成目标表的查询SQL。这两个方法会根据输入参数中的`actual_execute_sql`和`expected_execute_sql`模板生成具体的SQL语句,并对结果列名进行唯一性处理,以避免列名冲突。 + +### 结果验证阶段 + +结果验证阶段由`buildSinkConfigs`方法处理,该方法构建了结果存储配置。系统会生成用于存储验证结果的SQL语句,这些语句会将实际值和期望值进行比较,并根据预设的比较运算符和阈值判断检查是否通过。验证结果会被存储到`dv_job_execution_result`表中,而实际值和期望值则会被存储到`dv_actual_values`表中。 + +```mermaid +sequenceDiagram +participant 配置构建 as 配置构建 +participant SQL生成 as SQL生成 +participant 执行引擎 as 执行引擎 +participant 结果验证 as 结果验证 +配置构建->>SQL生成 : 提供配置参数 +SQL生成->>SQL生成 : 生成实际值SQL +SQL生成->>SQL生成 : 生成期望值SQL +SQL生成->>执行引擎 : 提交执行任务 +执行引擎->>执行引擎 : 执行SQL查询 +执行引擎->>结果验证 : 返回查询结果 +结果验证->>结果验证 : 比较实际值与期望值 +结果验证->>结果验证 : 应用比较运算符和阈值 +结果验证->>结果验证 : 生成验证结果 +结果验证->>存储系统 : 保存结果数据 +``` + +**图表来源** +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L86-L102) +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L105-L139) + +**本节来源** +- [LocalMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-config\src\main\java\io\datavines\engine\local\config\LocalMultiTableValueComparisonMetricBuilder.java#L48-L140) + +## 实际使用案例 + +### 案例一:数据迁移验证 + +在将数据从旧系统迁移到新系统的场景中,可以使用两表值比较检查来验证迁移的准确性。假设需要验证用户表的数据迁移情况,可以配置如下参数: + +- 源表: `old_system.users` +- 目标表: `new_system.users` +- 比较字段: `user_id`, `balance` +- 比较运算符: 等于(=) +- 阈值: 0 (要求完全一致) + +系统会分别从两个表中查询用户余额,并比较对应用户ID的余额是否一致。如果所有用户的余额都一致,则检查通过;否则,检查失败并记录差异详情。 + +### 案例二:数据同步监控 + +在跨数据中心的数据同步场景中,可以使用两表值比较检查来监控数据同步的延迟和准确性。例如,监控订单表的同步情况: + +- 源表: `primary_dc.orders` +- 目标表: `secondary_dc.orders` +- 比较字段: `order_id`, `total_amount` +- 比较运算符: 等于(=) +- 阈值: 0.01 (允许0.01的舍入误差) +- 过滤条件: `order_date = '${system.biz.date}'` (只比较当天的订单) + +这种配置可以定期检查主备数据中心的订单数据是否一致,允许微小的舍入误差,但要求主要数据保持一致。 + +## 常见问题解决方案 + +### 问题一:列名冲突 + +**问题描述**: 当源表和目标表有相同名称的列时,可能会导致SQL执行错误。 + +**解决方案**: 在生成SQL时,系统会对实际值和期望值的列名添加唯一键后缀,如`actual_value_{metric_unique_key}`和`expected_value_{metric_unique_key}`,避免列名冲突。 + +### 问题二:数据类型不匹配 + +**问题描述**: 源表和目标表的比较字段数据类型不一致,导致比较失败。 + +**解决方案**: 在配置时确保两个字段的数据类型兼容,或在SQL查询中使用类型转换函数。例如,将字符串类型的数值转换为数值类型进行比较。 + +### 问题三:性能问题 + +**问题描述**: 当比较的表数据量很大时,查询性能可能成为瓶颈。 + +**解决方案**: +1. 在比较字段上创建索引 +2. 使用适当的过滤条件缩小数据范围 +3. 考虑使用增量比较而非全量比较 +4. 优化查询SQL,避免全表扫描 + +### 问题四:网络延迟影响 + +**问题描述**: 当源表和目标表位于不同的数据库实例时,网络延迟可能影响比较结果的实时性。 + +**解决方案**: +1. 在非高峰时段执行比较 +2. 增加合理的阈值以容忍短暂的数据不一致 +3. 使用异步比较模式,将比较结果存储后进行分析 + +## 结论 + +两表值比较检查是DataVines数据质量框架中重要的数据验证工具,它通过系统化的配置和执行流程,确保了跨表数据的一致性和准确性。该功能具有良好的扩展性,支持多种数据源和数据库类型,并通过插件化架构实现了灵活的配置和执行。 + +通过合理配置比较参数和优化执行策略,两表值比较检查可以有效应用于数据迁移验证、数据同步监控、数据质量审计等多种业务场景,为数据驱动的决策提供可靠的质量保障。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\345\207\206\347\241\256\346\200\247\346\243\200\346\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\345\207\206\347\241\256\346\200\247\346\243\200\346\237\245.md" new file mode 100644 index 00000000..ad77ed90 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\345\207\206\347\241\256\346\200\247\346\243\200\346\237\245.md" @@ -0,0 +1,482 @@ +# 跨表准确性检查 + + +**本文档引用的文件** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) +- [submit_job_mysql_storage.json](file://datavines-runner\src\main\resources\submit_job_mysql_storage.json) + + +## 目录 +1. [引言](#引言) +2. [业务场景](#业务场景) +3. [配置参数说明](#配置参数说明) +4. [MultiTableAccuracy类实现分析](#multitableaccuracy类实现分析) +5. [数据比对算法与结果计算](#数据比对算法与结果计算) +6. [配置示例与使用场景](#配置示例与使用场景) +7. [大数据量下的性能优化建议](#大数据量下的性能优化建议) +8. [结论](#结论) + +## 引言 + +跨表准确性检查是DataVines数据质量框架中的一个重要功能,用于验证两个数据表之间的数据一致性。该功能通过比较源表和目标表的数据,识别出不一致的记录,并提供详细的错误数据输出。本文档将深入分析跨表准确性检查的实现原理、配置方法和使用场景,为用户提供全面的技术指导。 + +**本节来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) + +## 业务场景 + +跨表准确性检查适用于多种数据质量验证场景,主要包括: + +1. **数据迁移验证**:在数据从一个系统迁移到另一个系统后,验证源表和目标表的数据是否一致。 +2. **数据同步监控**:在实时或批量数据同步过程中,定期检查源端和目标端的数据一致性。 +3. **ETL过程验证**:在ETL(抽取、转换、加载)流程中,验证转换前后的数据是否保持一致。 +4. **数据备份验证**:验证主数据库和备份数据库之间的数据一致性。 +5. **多源数据整合**:在将多个数据源整合到一个目标表时,验证整合过程的准确性。 + +这些场景都需要确保数据在不同表之间的准确性和完整性,跨表准确性检查功能能够有效满足这些需求。 + +**本节来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) + +## 配置参数说明 + +跨表准确性检查功能通过一系列配置参数来定义数据比对的规则和条件。以下是主要配置参数的详细说明: + +### 核心配置参数 + +| 参数名称 | 描述 | 示例 | +|--------|------|------| +| `table` | 源表名称 | `"users"` | +| `table2` | 目标表名称 | `"users_backup"` | +| `database` | 源表所在数据库 | `"production"` | +| `database2` | 目标表所在数据库 | `"backup"` | +| `mapping_columns` | 映射列配置,定义源表和目标表之间的列对应关系 | `[{"column":"id","column2":"user_id"},{"column":"name","column2":"full_name"}]` | +| `filter` | 源表过滤条件 | `"status = 'active'"` | +| `filter2` | 目标表过滤条件 | `"deleted = 0"` | + +### 关联键配置 + +关联键是跨表准确性检查的核心,用于确定源表和目标表中哪些记录应该进行比较。关联键通过`mapping_columns`参数配置,每个映射列定义了源表列和目标表列的对应关系。 + +```json +{ + "mapping_columns": [ + { + "column": "user_id", + "column2": "id", + "operator": "=" + }, + { + "column": "email", + "column2": "email_address", + "operator": "=" + } + ] +} +``` + +### 过滤条件配置 + +过滤条件允许用户在比对前对源表和目标表的数据进行筛选,只比对符合条件的记录。 + +```json +{ + "filter": "created_date >= '2023-01-01'", + "filter2": "status = 'active'" +} +``` + +### 别名配置 + +为了在SQL查询中区分源表和目标表,系统会自动为它们分配别名。 + +| 参数 | 描述 | +|------|------| +| `table_alias` | 源表别名 | +| `table2_alias` | 目标表别名 | + +**本节来源** +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) + +## MultiTableAccuracy类实现分析 + +`MultiTableAccuracy`类是跨表准确性检查功能的核心实现,它实现了`SqlMetric`接口,提供了数据比对所需的所有方法。 + +### 类结构与继承关系 + +```mermaid +classDiagram +class SqlMetric { +<> ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++isInvalidateItemsCanOutput() boolean ++getInvalidateItems(Map~String,String~) ExecuteSql ++getActualValue(Map~String,String~) ExecuteSql ++getDirectActualValue(Map~String,String~) ExecuteSql ++validateConfig(Map~String,Object~) CheckResult ++getConfigMap() Map~String,ConfigItem~ ++prepare(Map~String,String~) void +} +class MultiTableAccuracy { +-sourceTableSql StringBuilder +-targetTableSql StringBuilder +-invalidateItemsSql StringBuilder ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++isInvalidateItemsCanOutput() boolean ++validateConfig(Map~String,Object~) CheckResult ++prepare(Map~String,String~) void ++getConfigMap() Map~String,ConfigItem~ ++getInvalidateItems(Map~String,String~) ExecuteSql ++getActualValue(Map~String,String~) ExecuteSql ++getDirectActualValue(Map~String,String~) ExecuteSql ++suitableType() DataVinesDataType[] +} +MultiTableAccuracy --|> SqlMetric : 实现 +``` + +**图表来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) +- [SqlMetric.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\SqlMetric.java) + +### 核心字段 + +`MultiTableAccuracy`类定义了三个核心的`StringBuilder`字段,用于构建SQL查询语句: + +- `sourceTableSql`:存储源表的SELECT查询语句模板 +- `targetTableSql`:存储目标表的SELECT查询语句模板 +- `invalidateItemsSql`:存储用于查找不一致记录的SQL查询语句模板 + +### 主要方法分析 + +#### prepare方法 + +`prepare`方法是配置预处理的核心,它根据用户提供的配置参数构建最终的SQL查询语句。 + +```mermaid +flowchart TD +Start([开始]) --> CheckFilter["检查filter参数"] +CheckFilter --> |存在且非空| AppendFilter["在sourceTableSql后添加WHERE子句"] +CheckFilter --> |不存在或为空| SkipFilter["跳过"] +SkipFilter --> CheckFilter2["检查filter2参数"] +AppendFilter --> CheckFilter2 +CheckFilter2 --> |存在且非空| AppendFilter2["在targetTableSql后添加WHERE子句"] +CheckFilter2 --> |不存在或为空| SkipFilter2["跳过"] +SkipFilter2 --> BuildInvalidateSql["构建invalidateItemsSql"] +AppendFilter2 --> BuildInvalidateSql +BuildInvalidateSql --> End([结束]) +``` + +**图表来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) + +#### getInvalidateItems方法 + +`getInvalidateItems`方法生成用于查找不一致记录的SQL查询。 + +```mermaid +sequenceDiagram +participant User as 用户 +participant MultiTableAccuracy as MultiTableAccuracy +participant ExecuteSql as ExecuteSql +User->>MultiTableAccuracy : getInvalidateItems(inputParameter) +MultiTableAccuracy->>MultiTableAccuracy : 获取METRIC_UNIQUE_KEY +MultiTableAccuracy->>ExecuteSql : 创建ExecuteSql实例 +ExecuteSql->>ExecuteSql : 设置resultTable为"invalidate_items_" + uniqueKey +ExecuteSql->>ExecuteSql : 设置sql为invalidateItemsSql.toString() +ExecuteSql->>ExecuteSql : 设置errorOutput为true +MultiTableAccuracy-->>User : 返回ExecuteSql实例 +``` + +**图表来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) + +**本节来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) + +## 数据比对算法与结果计算 + +跨表准确性检查的数据比对算法基于SQL的LEFT JOIN操作,通过精心设计的查询语句来识别不一致的记录。 + +### 数据比对算法 + +跨表准确性检查使用以下算法来识别不一致的记录: + +1. **LEFT JOIN比对**:使用LEFT JOIN将源表和目标表连接起来,基于配置的关联键。 +2. **空值检测**:在JOIN结果中,检测目标表的关联键是否为空,为空表示源表中的记录在目标表中不存在。 +3. **数据一致性检查**:对于JOIN成功的记录,比较其他字段的值是否一致。 + +```sql +SELECT + ${table_alias_columns}, + ${table2_alias_columns} +FROM + (SELECT * FROM ${table} WHERE (${filter})) ${table_alias} + LEFT JOIN + (SELECT * FROM ${table2} WHERE (${filter2})) ${table2_alias} +ON ${on_clause} +WHERE ${where_clause} +``` + +其中,`on_clause`定义了关联键的匹配条件,`where_clause`定义了不一致记录的判断条件。 + +### 结果计算方式 + +系统通过两个步骤来计算最终的检查结果: + +#### 1. 不一致记录查询 + +首先执行`getInvalidateItems`方法生成的SQL查询,获取所有不一致的记录。 + +#### 2. 不一致记录计数 + +然后执行`getActualValue`方法生成的SQL查询,统计不一致记录的数量。 + +```sql +SELECT COUNT(1) AS actual_value_${uniqueKey} +FROM ${invalidate_items_table} +``` + +这个计数值将作为实际值,与预期值进行比较,以确定数据质量检查是否通过。 + +### ON子句生成逻辑 + +ON子句的生成由`MetricParserUtils.getOnClause`方法完成,它根据`mapping_columns`配置生成关联条件。 + +```mermaid +flowchart TD +Start([开始]) --> ForEachColumn["遍历mapping_columns中的每个列"] +ForEachColumn --> BuildCoalesce["构建COALESCE表达式"] +BuildCoalesce --> AddOperator["添加比较操作符"] +AddOperator --> NextColumn["下一个列"] +NextColumn --> |还有列| ForEachColumn +NextColumn --> |没有列| JoinWithAND["用AND连接所有条件"] +JoinWithAND --> End([返回ON子句]) +``` + +**图表来源** +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) + +### WHERE子句生成逻辑 + +WHERE子句的生成由`MetricParserUtils.getWhereClause`方法完成,它定义了不一致记录的判断条件。 + +```mermaid +flowchart TD +Start([开始]) --> NotNullCheck["检查源表关联键不为空"] +NotNullCheck --> NullCheck["检查目标表关联键为空"] +NullCheck --> CombineConditions["组合条件: NOT(源表为空) AND 目标表为空"] +CombineConditions --> End([返回WHERE子句]) +``` + +**图表来源** +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) + +**本节来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) + +## 配置示例与使用场景 + +### 完整配置示例 + +以下是一个完整的跨表准确性检查配置示例: + +```json +{ + "languageEn": true, + "name": "cross_table_accuracy_check", + "executePlatformType": "spark", + "parameter": { + "connectorParameter": { + "type": "mysql", + "parameters": { + "database": "production", + "password": "password", + "port": "3306", + "host": "prod-db.example.com", + "user": "reader", + "properties": "useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai" + } + }, + "connectorParameter2": { + "type": "mysql", + "parameters": { + "database": "backup", + "password": "password", + "port": "3306", + "host": "backup-db.example.com", + "user": "reader", + "properties": "useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai" + } + }, + "metricParameterList": [ + { + "metricType": "multi_table_accuracy", + "metricParameter": { + "table": "users", + "table2": "users_backup", + "database": "production", + "database2": "backup", + "mapping_columns": "[{\"column\":\"user_id\",\"column2\":\"id\",\"operator\":\"=\"},{\"column\":\"email\",\"column2\":\"email_address\",\"operator\":\"=\"}]", + "filter": "created_date >= '2023-01-01'", + "filter2": "status = 'active'", + "expected_type": "fix_value", + "expected_parameter": { + "expected_value": "0" + }, + "result_formula": "count", + "operator": "eq", + "threshold": 0.0 + } + } + ] + }, + "errorDataStorageType": "file", + "errorDataStorageParameter": { + "data_dir": "/tmp/datavines/error-data", + "column_separator": "," + }, + "validateResultDataStorageType": "mysql", + "validateResultDataStorageParameter": { + "database": "dq_results", + "password": "password", + "port": "3306", + "host": "results-db.example.com", + "user": "writer", + "properties": "useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai" + } +} +``` + +### 典型使用场景 + +#### 场景1:数据迁移验证 + +在将用户数据从旧系统迁移到新系统后,验证数据的完整性。 + +```json +{ + "table": "users_v1", + "table2": "users_v2", + "mapping_columns": "[{\"column\":\"id\",\"column2\":\"user_id\",\"operator\":\"=\"}]", + "filter": "status = 'active'", + "filter2": "deleted = 0" +} +``` + +#### 场景2:ETL过程监控 + +在每日ETL流程后,验证事实表和维度表的数据一致性。 + +```json +{ + "table": "fact_orders", + "table2": "dim_customers", + "mapping_columns": "[{\"column\":\"customer_id\",\"column2\":\"id\",\"operator\":\"=\"}]", + "filter": "order_date = CURRENT_DATE - 1", + "filter2": "status = 'active'" +} +``` + +#### 场景3:多数据中心同步验证 + +在主备数据中心之间,验证关键业务表的数据同步情况。 + +```json +{ + "table": "transactions", + "table2": "transactions", + "database": "finance", + "database2": "finance", + "connectorParameter": { + "host": "primary-dc.example.com" + }, + "connectorParameter2": { + "host": "secondary-dc.example.com" + }, + "mapping_columns": "[{\"column\":\"transaction_id\",\"column2\":\"transaction_id\",\"operator\":\"=\"}]" +} +``` + +**本节来源** +- [submit_job_mysql_storage.json](file://datavines-runner\src\main\resources\submit_job_mysql_storage.json) +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) + +## 大数据量下的性能优化建议 + +当处理大规模数据集时,跨表准确性检查可能会面临性能挑战。以下是一些性能优化建议: + +### 1. 合理使用过滤条件 + +通过`filter`和`filter2`参数限制比对的数据范围,避免全表扫描。 + +```json +{ + "filter": "created_date >= '2023-01-01' AND created_date < '2023-02-01'", + "filter2": "status = 'active'" +} +``` + +### 2. 确保关联键上有索引 + +在源表和目标表的关联键上创建索引,可以显著提高JOIN操作的性能。 + +### 3. 分批处理大数据集 + +对于超大规模的数据集,考虑分批处理,按时间范围或ID范围分批进行比对。 + +### 4. 使用合适的执行平台 + +根据数据规模选择合适的执行平台: +- 小规模数据:使用`local`执行平台 +- 中大规模数据:使用`spark`执行平台 +- 实时流数据:使用`flink`执行平台 + +### 5. 优化JOIN策略 + +在Spark等分布式计算框架中,可以通过配置优化JOIN策略: + +```java +// 在Spark配置中设置JOIN优化参数 +configuration.set("spark.sql.adaptive.enabled", "true"); +configuration.set("spark.sql.adaptive.coalescePartitions.enabled", "true"); +``` + +### 6. 减少数据传输 + +只选择必要的列进行比对,避免SELECT *操作。 + +```json +{ + "mapping_columns": "[{\"column\":\"id\",\"column2\":\"user_id\",\"operator\":\"=\"},{\"column\":\"email\",\"column2\":\"email_address\",\"operator\":\"=\"}]" +} +``` + +### 7. 监控和调优 + +定期监控跨表准确性检查的执行时间和资源消耗,根据监控结果进行调优。 + +**本节来源** +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java) +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) + +## 结论 + +跨表准确性检查是DataVines数据质量框架中一个强大而灵活的功能,能够有效验证两个数据表之间的数据一致性。通过本文档的详细分析,我们了解了其业务场景、配置参数、实现原理和使用方法。 + +`MultiTableAccuracy`类通过巧妙的SQL查询设计,利用LEFT JOIN和空值检测算法,准确识别出不一致的记录。配置系统的灵活性允许用户根据具体需求定义复杂的比对规则,包括关联键、过滤条件和映射关系。 + +在实际应用中,用户应根据数据规模和业务需求合理配置参数,并采用适当的性能优化策略,以确保跨表准确性检查的高效执行。随着数据量的增长,分布式计算平台如Spark和Flink的优势将更加明显,能够处理更大规模的数据比对任务。 + +总之,跨表准确性检查功能为数据质量管理提供了重要的技术支撑,帮助组织确保数据的准确性和可靠性,为数据驱动的决策提供坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231.md" new file mode 100644 index 00000000..5766669d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\206\205\347\275\256\345\272\246\351\207\217\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231/\350\267\250\350\241\250\346\243\200\346\237\245\350\247\204\345\210\231.md" @@ -0,0 +1,210 @@ +# 跨表检查规则 + + +**本文档引用的文件** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java) +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java) +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java) +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java) +- [SparkSinkSqlBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSinkSqlBuilder.java) + + +## 目录 +1. [引言](#引言) +2. [跨表准确性检查](#跨表准确性检查) +3. [两表值比对检查](#两表值比对检查) +4. [核心实现类分析](#核心实现类分析) +5. [源表与目标表映射配置](#源表与目标表映射配置) +6. [数据一致性验证最佳实践](#数据一致性验证最佳实践) +7. [性能优化建议](#性能优化建议) +8. [结论](#结论) + +## 引言 + +跨表检查规则是数据质量管理系统中的关键组成部分,用于验证不同数据表之间的数据一致性和准确性。本系统提供了两种主要的跨表检查规则:跨表准确性检查和两表值比对检查。这些规则通过比较源表和目标表的数据,确保数据在不同系统或不同时间点之间保持一致。跨表准确性检查主要用于验证源表中的记录是否在目标表中存在,而两表值比对检查则用于比较两个表中对应字段的值是否相等。这两种规则在数据迁移、数据同步和数据集成等场景中具有重要应用价值。 + +## 跨表准确性检查 + +跨表准确性检查规则用于验证源表中的记录是否在目标表中存在。该规则通过执行LEFT JOIN操作来识别源表中存在但目标表中缺失的记录。具体实现中,系统会构建一个包含源表和目标表的LEFT JOIN查询,其中连接条件由用户配置的字段映射关系决定。查询结果将包含源表和目标表中所有匹配和不匹配的记录,通过WHERE子句筛选出目标表中为NULL的记录,即为不一致的数据项。 + +该规则的执行流程如下:首先,系统会根据配置构建源表和目标表的SELECT语句;然后,根据字段映射关系构建ON子句;最后,组合成完整的LEFT JOIN查询语句。查询结果可以输出到指定的错误数据存储中,便于后续分析和处理。 + +```mermaid +flowchart TD +Start([开始]) --> BuildSourceQuery["构建源表查询语句"] +BuildSourceQuery --> BuildTargetQuery["构建目标表查询语句"] +BuildTargetQuery --> BuildJoinCondition["根据字段映射构建JOIN条件"] +BuildJoinCondition --> ConstructQuery["构造LEFT JOIN查询"] +ConstructQuery --> ExecuteQuery["执行查询"] +ExecuteQuery --> FilterNull["筛选目标表字段为NULL的记录"] +FilterNull --> OutputResult["输出不一致数据项"] +OutputResult --> End([结束]) +``` + +**图来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L34-L38) + +**本节来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L32-L136) + +## 两表值比对检查 + +两表值比对检查规则用于比较两个表中对应字段的值是否相等。与跨表准确性检查不同,该规则不仅关注记录的存在性,还关注字段值的一致性。该规则通过构建包含两个表的查询,比较对应字段的值来识别不一致的数据。 + +该规则的实现相对简单,主要通过配置两个表的连接条件和需要比较的字段来完成。系统会为每个需要比较的字段生成相应的比较表达式,并在查询结果中标识不一致的记录。与跨表准确性检查相比,两表值比对检查不支持输出具体的不一致数据项,而是仅返回不一致记录的数量。 + +```mermaid +flowchart TD +Start([开始]) --> ConfigureTables["配置源表和目标表"] +ConfigureTables --> DefineMapping["定义字段映射关系"] +DefineMapping --> BuildComparison["构建字段值比较逻辑"] +BuildComparison --> ExecuteComparison["执行值比较查询"] +ExecuteComparison --> CountInconsistencies["统计不一致记录数量"] +CountInconsistencies --> ReturnResult["返回结果"] +ReturnResult --> End([结束]) +``` + +**图来源** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java#L31-L87) + +**本节来源** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java#L31-L87) + +## 核心实现类分析 + +### MultiTableAccuracy类 + +MultiTableAccuracy类是跨表准确性检查规则的核心实现。该类实现了SqlMetric接口,提供了跨表准确性检查所需的所有功能。类的主要成员变量包括sourceTableSql、targetTableSql和invalidateItemsSql,分别用于存储源表查询、目标表查询和不一致数据项查询的SQL模板。 + +该类的关键方法包括: +- prepare方法:根据配置参数准备SQL查询,包括添加过滤条件和构建JOIN语句 +- getInvalidateItems方法:生成用于查询不一致数据项的SQL语句 +- getActualValue方法:生成用于统计不一致记录数量的SQL语句 +- getDirectActualValue方法:生成直接统计不一致记录数量的SQL语句,无需创建视图 + +```mermaid +classDiagram +class MultiTableAccuracy { +-StringBuilder sourceTableSql +-StringBuilder targetTableSql +-StringBuilder invalidateItemsSql ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++isInvalidateItemsCanOutput() boolean ++validateConfig(Map~String, Object~) CheckResult ++prepare(Map~String, String~) void ++getConfigMap() Map~String, ConfigItem~ ++getInvalidateItems(Map~String, String~) ExecuteSql ++getActualValue(Map~String, String~) ExecuteSql ++getDirectActualValue(Map~String, String~) ExecuteSql ++suitableType() DataVinesDataType[] +} +SqlMetric <|-- MultiTableAccuracy +``` + +**图来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L32-L136) + +**本节来源** +- [MultiTableAccuracy.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-accuracy\src\main\java\io\datavines\metric\plugin\MultiTableAccuracy.java#L32-L136) + +### MultiTableValueComparison类 + +MultiTableValueComparison类是两表值比对检查规则的核心实现。与MultiTableAccuracy类相比,该类的实现更为简单,因为它不支持输出具体的不一致数据项。该类同样实现了SqlMetric接口,但其关键方法如getInvalidateItems和getActualValue均返回null,表示不支持这些功能。 + +```mermaid +classDiagram +class MultiTableValueComparison { ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++isInvalidateItemsCanOutput() boolean ++getInvalidateItems(Map~String, String~) ExecuteSql ++getActualValue(Map~String, String~) ExecuteSql ++validateConfig(Map~String, Object~) CheckResult ++getConfigMap() Map~String, ConfigItem~ ++prepare(Map~String, String~) void ++suitableType() DataVinesDataType[] +} +SqlMetric <|-- MultiTableValueComparison +``` + +**图来源** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java#L31-L87) + +**本节来源** +- [MultiTableValueComparison.java](file://datavines-metric\datavines-metric-plugins\datavines-metric-multi-table-value-comparison\src\main\java\io\datavines\metric\plugin\MultiTableValueComparison.java#L31-L87) + +## 源表与目标表映射配置 + +源表与目标表的映射关系是跨表检查规则的核心配置。系统通过MappingColumn类来定义字段映射关系,每个MappingColumn对象包含源表字段名、目标表字段名和比较操作符。在配置映射关系时,需要确保源表和目标表的对应字段具有兼容的数据类型。 + +配置过程主要在MetricParserUtils类中完成,该类提供了多个静态方法来处理映射关系: +- getTableAliasColumns:根据映射关系生成字段别名 +- getOnClause:根据映射关系生成JOIN条件 +- getWhereClause:生成筛选不一致记录的WHERE条件 + +```mermaid +sequenceDiagram +participant Config as 配置系统 +participant Parser as MetricParserUtils +participant Builder as SparkMultiTableAccuracyMetricBuilder +participant Executor as 执行引擎 +Config->>Parser : 提供字段映射列表 +Parser->>Parser : 处理映射关系 +Parser-->>Builder : 返回处理后的配置参数 +Builder->>Builder : 构建转换配置 +Builder->>Executor : 提交执行配置 +Executor->>Executor : 执行跨表检查 +Executor-->>Config : 返回检查结果 +``` + +**图来源** +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java#L172-L184) +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java#L44-L63) + +**本节来源** +- [MetricParserUtils.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\MetricParserUtils.java#L172-L223) +- [SparkMultiTableAccuracyMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableAccuracyMetricBuilder.java#L44-L63) + +## 数据一致性验证最佳实践 + +在实施跨表检查规则时,应遵循以下最佳实践以确保数据一致性验证的有效性和可靠性: + +1. **选择合适的主键字段**:在配置字段映射时,应优先选择具有唯一性的字段作为连接条件,以确保比较的准确性。 + +2. **合理设置过滤条件**:通过filter和filter2参数可以为源表和目标表设置过滤条件,这有助于缩小比较范围,提高检查效率。 + +3. **分批处理大数据集**:对于包含大量数据的表,建议分批进行检查,避免单次查询负载过大。 + +4. **定期执行检查**:将跨表检查规则纳入定期数据质量检查流程,及时发现和解决数据不一致问题。 + +5. **结合业务规则验证**:除了技术层面的字段比较,还应结合业务规则进行验证,确保数据不仅在技术上一致,在业务上也正确。 + +6. **监控和告警**:为跨表检查规则设置监控和告警机制,当发现数据不一致时能够及时通知相关人员。 + +## 性能优化建议 + +为提高跨表检查规则的执行性能,建议采取以下优化措施: + +1. **索引优化**:确保源表和目标表的连接字段上有适当的索引,这可以显著提高JOIN操作的性能。 + +2. **分区表利用**:如果表是分区的,尽量在查询中包含分区条件,以减少扫描的数据量。 + +3. **数据类型匹配**:确保比较的字段具有相同或兼容的数据类型,避免隐式类型转换带来的性能开销。 + +4. **查询优化**:对于复杂的跨表检查,可以考虑使用物化视图或临时表来存储中间结果,避免重复计算。 + +5. **资源分配**:根据数据量大小合理分配执行引擎的计算资源,确保有足够的内存和CPU资源处理查询。 + +6. **并行执行**:对于多个独立的跨表检查任务,可以考虑并行执行以提高整体效率。 + +7. **缓存机制**:对于频繁执行的跨表检查,可以考虑实现结果缓存机制,避免重复执行相同的查询。 + +## 结论 + +跨表检查规则是确保数据质量的重要手段,通过跨表准确性检查和两表值比对检查两种规则,可以有效验证不同数据表之间的数据一致性。MultiTableAccuracy和MultiTableValueComparison类作为核心实现,提供了灵活的配置选项和高效的执行逻辑。通过合理配置源表和目标表的映射关系,并遵循最佳实践和性能优化建议,可以充分发挥跨表检查规则的作用,确保数据的准确性和一致性。在实际应用中,应根据具体的业务需求和数据特点选择合适的检查规则,并持续监控和优化其执行性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\272\246\351\207\217API\346\216\245\345\217\243.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\272\246\351\207\217API\346\216\245\345\217\243.md" new file mode 100644 index 00000000..452cf47c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\345\272\246\351\207\217API\346\216\245\345\217\243.md" @@ -0,0 +1,282 @@ +# 度量API接口 + + +**本文档引用的文件** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java) +- [MetricExecutionResult.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricExecutionResult.java) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [MetricLevel.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricLevel.java) +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) +- [ConfigItem.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ConfigItem.java) +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) + + +## 目录 +1. [引言](#引言) +2. [核心接口概述](#核心接口概述) +3. [SqlMetric接口详解](#sqlmetric接口详解) +4. [MetricValidator验证逻辑](#metricvalidator验证逻辑) +5. [MetricConstants常量定义](#metricconstants常量定义) +6. [MetricExecutionResult数据结构](#metricexecutionresult数据结构) +7. [接口继承关系与实现示例](#接口继承关系与实现示例) +8. [典型实现分析](#典型实现分析) +9. [构建新的度量规则指南](#构建新的度量规则指南) +10. [总结](#总结) + +## 引言 +本文档旨在详细说明DataVines系统中`datavines-metric`模块的核心API接口设计。该模块为数据质量度量提供了标准化的接口体系,支持多种数据质量维度的检查和评估。通过统一的接口定义,系统实现了可扩展的度量规则框架,允许用户基于标准接口开发自定义的度量规则。 + +## 核心接口概述 +`datavines-metric`模块的核心由四个关键组件构成:`SqlMetric`接口定义了度量规则的基本行为和配置;`MetricValidator`类提供了结果验证的通用逻辑;`MetricConstants`定义了系统级常量;`MetricExecutionResult`则封装了度量执行的结果数据结构。这些组件共同构成了数据质量度量的基础框架。 + +```mermaid +classDiagram +class SqlMetric { +<> ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++getLevel() MetricLevel ++isInvalidateItemsCanOutput() boolean ++getInvalidateItems(Map) ExecuteSql ++getActualValue(Map) ExecuteSql ++getDirectActualValue(Map) ExecuteSql ++getActualName() String ++getActualValueType() String ++validateConfig(Map) CheckResult ++getConfigMap() Map ++prepare(Map) void ++getIssue() String ++suitableType() List ++supportMultiple() boolean ++getMetricParameter(Map) List ++getDirectionType() MetricDirectionType ++isCustomSql() boolean +} +class MetricValidator { ++isSuccess(MetricExecutionResult) boolean ++getQualityScore(MetricExecutionResult, boolean) BigDecimal ++getCompareResult(OperatorType, BigDecimal, BigDecimal) boolean +} +class MetricConstants { ++RESULT_COLUMN_LIST List ++ACTUAL_COLUMN_LIST List ++PROFILE_COLUMN_LIST List +} +class MetricExecutionResult { +-actualValue BigDecimal +-expectedValue BigDecimal +-resultFormula String +-operator String +-threshold BigDecimal +-expectedType String +-metricName String +-metricDimension String +-metricType String +-databaseName String +-tableName String +-columnName String ++MetricExecutionResult() ++MetricExecutionResult(Map) +} +class ResultFormula { +<> ++getName() String ++getZhName() String ++getResult(BigDecimal, BigDecimal) BigDecimal ++getScore(BigDecimal, BigDecimal, boolean, MetricDirectionType) BigDecimal ++getResultFormat(boolean) String ++getSymbol() String ++getType() ResultFormulaType +} +SqlMetric --> MetricExecutionResult : "生成" +MetricValidator --> MetricExecutionResult : "验证" +MetricValidator --> ResultFormula : "使用" +SqlMetric --> ResultFormula : "关联" +``` + +**接口来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java) +- [MetricExecutionResult.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricExecutionResult.java) +- [ResultFormula.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java) + +## SqlMetric接口详解 +`SqlMetric`接口是所有SQL度量规则的基础,通过SPI机制实现插件化扩展。该接口定义了度量规则执行、配置和结果处理的标准方法。 + +### 基本信息方法 +接口提供了获取度量规则基本信息的方法,包括英文名称`getName()`和中文名称`getZhName()`,以及通过`getNameByLanguage(boolean)`方法根据语言环境选择合适的名称显示。 + +### 度量分类方法 +`getDimension()`方法返回度量所属的维度,如完整性、一致性等;`getType()`方法返回度量类型,区分单表、多表等不同场景;`getLevel()`方法定义度量的粒度级别,如数据库级、表级或列级。 + +### SQL执行方法 +核心的SQL执行方法包括: +- `getInvalidateItems()`:获取无效项的执行SQL +- `getActualValue()`:获取实际值的执行SQL +- `getDirectActualValue()`:获取直接实际值的执行SQL(默认使用`getActualValue`) + +### 配置管理方法 +`validateConfig()`用于验证配置参数的正确性,`getConfigMap()`返回配置项映射,`prepare()`方法用于初始化配置准备。 + +### 扩展属性方法 +接口还定义了`suitableType()`指定适用的数据类型,`supportMultiple()`指示是否支持多实例,`getDirectionType()`定义指标方向(正向或负向)等扩展属性。 + +**接口来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) + +## MetricValidator验证逻辑 +`MetricValidator`类提供了度量结果验证的核心逻辑,主要包含两个静态方法: + +### 成功判断逻辑 +`isSuccess()`方法根据操作符类型、结果计算公式和阈值来判断度量结果是否成功。该方法首先从执行结果中提取实际值、期望值、操作符和阈值,然后通过`ResultFormula`插件计算结果值,最后调用`getCompareResult()`进行比较判断。 + +### 质量评分计算 +`getQualityScore()`方法计算度量的质量分数,结合实际值、期望值、成功状态和指标方向,通过`ResultFormula`插件的`getScore()`方法得出最终评分。 + +### 比较逻辑实现 +`getCompareResult()`私有方法实现了各种操作符(等于、小于、大于等)的比较逻辑,使用`BigDecimal.compareTo()`确保数值比较的精确性。 + +**接口来源** +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) + +## MetricConstants常量定义 +`MetricConstants`类定义了系统中使用的常量,主要包括三个静态列表: + +### 结果列定义 +`RESULT_COLUMN_LIST`定义了度量结果表的列结构,包含作业执行ID、度量唯一键、度量类型、实际值、期望值、操作符、阈值等关键字段。 + +### 实际值列定义 +`ACTUAL_COLUMN_LIST`定义了实际值存储表的列结构,包含作业执行ID、度量名称、唯一编码、实际值、数据时间和创建更新时间等字段。 + +### 档案列定义 +`PROFILE_COLUMN_LIST`定义了数据档案表的列结构,用于存储数据特征分析结果。 + +这些常量在系统初始化时被静态块填充,确保了数据表结构的一致性和可维护性。 + +**接口来源** +- [MetricConstants.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java) + +## MetricExecutionResult数据结构 +`MetricExecutionResult`类是度量执行结果的核心数据结构,采用Lombok注解简化代码,实现了`Serializable`接口支持序列化。 + +### 核心属性 +该类包含以下核心属性: +- `actualValue`:实际测量值 +- `expectedValue`:期望值 +- `resultFormula`:结果计算公式 +- `operator`:比较操作符 +- `threshold`:阈值 +- `metricName`:度量名称 +- `metricDimension`:度量维度 +- `metricType`:度量类型 +- `databaseName`、`tableName`、`columnName`:目标对象标识 + +### 构造方法 +提供了两个构造方法:无参构造方法用于反射创建实例;带`Map`参数的构造方法用于从数据映射创建实例,自动处理空值检查和类型转换。 + +### 数据类型处理 +所有数值类型均使用`BigDecimal`以确保精度,字符串类型进行trim处理去除空白字符,体现了对数据质量的严格要求。 + +**接口来源** +- [MetricExecutionResult.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricExecutionResult.java) + +## 接口继承关系与实现示例 +`datavines-metric`模块采用接口继承和抽象基类相结合的设计模式,形成了清晰的层次结构。 + +```mermaid +classDiagram +class SqlMetric { +<> +} +class BaseSingleTable { ++prepare(Map) void ++getConfigMap() Map ++getMetricParameter(Map) List +} +class BaseSingleTableColumnNotUseView { ++getDirectActualValue(Map) ExecuteSql +} +SqlMetric <|-- BaseSingleTable +BaseSingleTable <|-- BaseSingleTableColumnNotUseView +BaseSingleTable <|-- TableRowCount +BaseSingleTableColumnNotUseView <|-- ColumnNull +class TableRowCount { ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++getActualValue(Map) ExecuteSql +} +class ColumnNull { ++getName() String ++getZhName() String ++getDimension() MetricDimension ++getType() MetricType ++prepare(Map) void +} +TableRowCount : 实现 +ColumnNull : 实现 +``` + +**接口来源** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) + +## 典型实现分析 +通过分析`TableRowCount`和`ColumnNull`两个典型实现,可以深入了解度量规则的具体实现方式。 + +### TableRowCount实现 +`TableRowCount`类继承自`BaseSingleTable`,实现了表行数检查功能: +- 定义了英文名"table_row_count"和中文名"表行数检查" +- 归属于完整性维度 +- 使用标准的COUNT(1) SQL查询获取实际值 +- 支持多表配置,通过`getMetricParameter()`方法处理逗号分隔的表名 + +### ColumnNull实现 +`ColumnNull`类继承自`BaseSingleTableColumnNotUseView`,实现了空值检查功能: +- 定义了英文名"column_null"和中文名"空值检查" +- 重写了`prepare()`方法,在准备阶段添加空值过滤条件 +- 指定适用的数据类型包括数值型、字符串型和日期时间型 +- 设置指标方向为负向,因为空值越多质量越差 + +这两个实现展示了如何基于基础接口和抽象类快速构建具体的度量规则。 + +**接口来源** +- [TableRowCount.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [ColumnNull.java](file://datavines-metric/datavines-metric-plugins/datavines-metric-column-null/src/main/java/io/datavines/metric/plugin/ColumnNull.java) + +## 构建新的度量规则指南 +基于现有API构建新的度量规则需要遵循以下步骤: + +### 继承合适的基类 +根据度量类型选择合适的基类继承: +- 单表度量:继承`BaseSingleTable` +- 单表列级度量:继承`BaseSingleTableColumnNotUseView` +- 自定义SQL度量:可直接实现`SqlMetric`接口 + +### 实现必要方法 +必须实现以下核心方法: +- `getName()`和`getZhName()`:提供度量名称 +- `getDimension()`:指定度量维度 +- `getType()`:定义度量类型 +- `getActualValue()`:生成实际值查询SQL + +### 配置管理 +通过`getConfigMap()`方法定义配置项,使用`ConfigItem`类封装配置信息,包括英文标签、中文标签和配置键。 + +### 验证逻辑 +重写`validateConfig()`方法确保配置参数的有效性,可在`prepare()`方法中进行初始化准备。 + +### 测试与注册 +实现完成后,需要编写相应的测试用例,并确保通过SPI机制正确注册到系统中。 + +## 总结 +`datavines-metric`模块的API设计体现了良好的面向接口编程思想和可扩展架构。通过`SqlMetric`接口定义标准,`MetricValidator`提供通用验证逻辑,`MetricConstants`统一常量管理,`MetricExecutionResult`规范数据结构,形成了完整的度量规则开发框架。开发者可以基于这些API快速构建新的度量规则,满足多样化的数据质量检查需求,同时保持系统的统一性和可维护性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\347\273\223\346\236\234\350\256\241\347\256\227\345\205\254\345\274\217.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\347\273\223\346\236\234\350\256\241\347\256\227\345\205\254\345\274\217.md" new file mode 100644 index 00000000..d6db5cfe --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\347\273\223\346\236\234\350\256\241\347\256\227\345\205\254\345\274\217.md" @@ -0,0 +1,333 @@ +# 结果计算公式 + + +**本文档中引用的文件** +- [Count.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-count\src\main\java\io\datavines\metric\result\formula\Count.java) +- [Diff.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff\src\main\java\io\datavines\metric\result\formula\Diff.java) +- [Percentage.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-percentage\src\main\java\io\datavines\metric\result\formula\Percentage.java) +- [DiffPercentage.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff-percentage\src\main\java\io\datavines\metric\result\formula\DiffPercentage.java) +- [ActualMinusExpectedDiff.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff-actual-expected\src\main\java\io\datavines\metric\result\formula\ActualMinusExpectedDiff.java) +- [ResultFormula.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormula.java) +- [ResultFormulaType.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormulaType.java) +- [SPI.java](file://datavines-spi\src\main\java\io\datavines\spi\SPI.java) +- [PluginLoader.java](file://datavines-spi\src\main\java\io\datavines\spi\PluginLoader.java) +- [MetricController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\MetricController.java) + + +## 目录 +1. [引言](#引言) +2. [核心公式功能说明](#核心公式功能说明) +3. [复合公式计算逻辑](#复合公式计算逻辑) +4. [公式插件的SPI扩展机制](#公式插件的spi扩展机制) +5. [公式执行流程分析](#公式执行流程分析) +6. [公式参数配置与组合使用](#公式参数配置与组合使用) +7. [公式选择指南](#公式选择指南) +8. [性能优化建议](#性能优化建议) +9. [复杂业务场景应用示例](#复杂业务场景应用示例) +10. [结论](#结论) + +## 引言 + +数据质量监控系统中的结果计算公式是衡量数据质量的核心组件。这些公式用于将实际测量值与期望值进行比较,从而生成有意义的质量指标。本文档详细说明了Count、Diff、Percentage等基础公式的功能,解释了ActualMinusExpectedDiff等复合公式的计算逻辑,分析了公式插件的SPI扩展机制和执行流程,并提供了公式参数配置、组合使用方法、选择指南和性能优化建议。 + +**本节不分析具体源文件,因此不提供来源** + +## 核心公式功能说明 + +在数据质量度量结果处理中,系统提供了多种基础计算公式来满足不同的业务需求: + +- **Count(计数)公式**:直接返回实际测量值,不进行任何计算。该公式适用于只需要记录原始测量结果的场景。 +- **Diff(差值)公式**:计算实际值与期望值之间的绝对差值,即|实际值-期望值|。该公式用于衡量偏差的绝对大小。 +- **Percentage(百分比)公式**:计算实际值相对于期望值的百分比,即实际值/期望值*100%。该公式用于衡量相对偏差。 +- **Diff-Percentage(差值百分比)公式**:计算实际值与期望值之间差值相对于期望值的百分比,即|实际值-期望值|/期望值*100%。该公式用于衡量相对偏差的大小。 + +这些公式通过实现`ResultFormula`接口来提供统一的计算方法,确保了系统的一致性和可扩展性。 + +**本节来源** +- [Count.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-count\src\main\java\io\datavines\metric\result\formula\Count.java) +- [Diff.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff\src\main\java\io\datavines\metric\result\formula\Diff.java) +- [Percentage.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-percentage\src\main\java\io\datavines\metric\result\formula\Percentage.java) +- [DiffPercentage.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff-percentage\src\main\java\io\datavines\metric\result\formula\DiffPercentage.java) + +## 复合公式计算逻辑 + +系统中的复合公式通过组合基础数学运算来实现更复杂的计算逻辑。以`ActualMinusExpectedDiff`为例,其计算逻辑如下: + +```mermaid +flowchart TD +Start([开始]) --> GetValues["获取实际值和期望值"] +GetValues --> Calculate["计算实际值-期望值"] +Calculate --> Return["返回计算结果"] +Return --> End([结束]) +``` + +**图示来源** +- [ActualMinusExpectedDiff.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff-actual-expected\src\main\java\io\datavines\metric\result\formula\ActualMinusExpectedDiff.java) + +`DiffPercentage`公式的计算逻辑更为复杂,需要处理除零异常和精度控制: + +```mermaid +flowchart TD +Start([开始]) --> CheckNull["检查期望值是否为空"] +CheckNull --> CheckZero{"期望值是否为0?"} +CheckZero --> |否| CalculateDiff["计算|实际值-期望值|"] +CheckZero --> |是| ReturnZero["返回0"] +CalculateDiff --> Divide["除以期望值"] +Divide --> Multiply["乘以100"] +Multiply --> Round["四舍五入保留4位小数"] +Round --> ReturnResult["返回结果"] +ReturnZero --> ReturnResult +ReturnResult --> End([结束]) +``` + +**图示来源** +- [DiffPercentage.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff-percentage\src\main\java\io\datavines\metric\result\formula\DiffPercentage.java) + +所有公式都使用`BigDecimal`类型进行计算,确保了高精度的数学运算,避免了浮点数计算中的精度丢失问题。 + +**本节来源** +- [ActualMinusExpectedDiff.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff-actual-expected\src\main\java\io\datavines\metric\result\formula\ActualMinusExpectedDiff.java) +- [DiffPercentage.java](file://datavines-metric\datavines-metric-result-formula-plugins\datavines-metric-result-formula-diff-percentage\src\main\java\io\datavines\metric\result\formula\DiffPercentage.java) + +## 公式插件的SPI扩展机制 + +系统采用SPI(Service Provider Interface)机制来实现公式的可扩展性。`ResultFormula`接口被`@SPI`注解标记,表明它是一个可扩展的接口: + +```mermaid +classDiagram +class ResultFormula { ++String getName() ++String getZhName() ++BigDecimal getResult(actualValue, expectedValue) ++BigDecimal getScore(actualValue, expectedValue, isSuccess, direction) ++String getResultFormat(isEn) ++String getSymbol() ++ResultFormulaType getType() +} +class Count { ++getResult(actualValue, expectedValue) +} +class Diff { ++getResult(actualValue, expectedValue) +} +class Percentage { ++getResult(actualValue, expectedValue) +} +class DiffPercentage { ++getResult(actualValue, expectedValue) +} +class ActualMinusExpectedDiff { ++getResult(actualValue, expectedValue) +} +ResultFormula <|-- Count +ResultFormula <|-- Diff +ResultFormula <|-- Percentage +ResultFormula <|-- DiffPercentage +ResultFormula <|-- ActualMinusExpectedDiff +``` + +**图示来源** +- [ResultFormula.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormula.java) +- [SPI.java](file://datavines-spi\src\main\java\io\datavines\spi\SPI.java) + +每个公式插件在`META-INF/plugins/`目录下都有一个配置文件,如`io.datavines.metric.api.ResultFormula`,其中定义了插件名称与实现类的映射关系: + +``` +count=io.datavines.metric.result.formula.Count +diff=io.datavines.metric.result.formula.Diff +percentage=io.datavines.metric.result.formula.Percentage +``` + +`PluginLoader`类负责加载这些插件,通过读取类路径下的配置文件,动态加载并实例化所有可用的公式实现。 + +**本节来源** +- [ResultFormula.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormula.java) +- [SPI.java](file://datavines-spi\src\main\java\io\datavines\spi\SPI.java) +- [PluginLoader.java](file://datavines-spi\src\main\java\io\datavines\spi\PluginLoader.java) + +## 公式执行流程分析 + +公式的执行流程从API请求开始,经过插件加载、实例化到最终计算结果的生成: + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "MetricController" +participant PluginLoader as "PluginLoader" +participant Formula as "ResultFormula" +Client->>Controller : GET /resultFormula/list +Controller->>PluginLoader : getSupportedPlugins() +PluginLoader->>PluginLoader : 加载所有公式插件 +PluginLoader-->>Controller : 返回插件名称列表 +Controller->>Controller : 创建Item对象列表 +Controller-->>Client : 返回公式列表 +Client->>Controller : 选择公式并提交计算请求 +Controller->>PluginLoader : getOrCreatePlugin(公式名称) +PluginLoader->>Formula : 实例化具体公式类 +PluginLoader-->>Controller : 返回公式实例 +Controller->>Formula : getResult(实际值, 期望值) +Formula-->>Controller : 返回计算结果 +Controller-->>Client : 返回最终结果 +``` + +**图示来源** +- [MetricController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\MetricController.java) +- [PluginLoader.java](file://datavines-spi\src\main\java\io\datavines\spi\PluginLoader.java) +- [ResultFormula.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormula.java) + +`PluginLoader`的加载过程包括: +1. 确定类加载器 +2. 查找`META-INF/plugins/`目录下的配置文件 +3. 读取配置文件中的类名映射 +4. 使用反射实例化类 +5. 缓存已加载的类以提高性能 + +**本节来源** +- [MetricController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\MetricController.java) +- [PluginLoader.java](file://datavines-spi\src\main\java\io\datavines\spi\PluginLoader.java) + +## 公式参数配置与组合使用 + +公式参数配置主要通过JSON格式的配置文件进行,支持灵活的组合使用。基本配置结构如下: + +```json +{ + "resultFormula": "diff-percentage", + "actualValue": 95, + "expectedValue": 100, + "metricDirection": "positive" +} +``` + +公式可以组合使用以满足复杂业务需求。例如,可以先使用`Count`公式获取原始计数值,然后使用`Percentage`公式计算其相对于基准值的百分比。系统支持通过配置文件定义公式执行链: + +```mermaid +flowchart LR +RawData[原始数据] --> Count["Count公式
获取计数值"] +Count --> Percentage["Percentage公式
计算百分比"] +Percentage --> DiffPercentage["Diff-Percentage公式
计算偏差百分比"] +DiffPercentage --> FinalResult[最终结果] +``` + +**图示来源** +- [ResultFormula.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormula.java) +- [ResultFormulaType.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormulaType.java) + +参数配置还支持国际化,通过`getNameByLanguage()`方法根据上下文语言返回相应的公式名称,确保了系统的多语言支持能力。 + +**本节来源** +- [ResultFormula.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormula.java) +- [ResultFormulaType.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormulaType.java) + +## 公式选择指南 + +根据不同的业务场景,应选择合适的计算公式: + +| 业务场景 | 推荐公式 | 说明 | +|---------|---------|------| +| 数据完整性检查 | Count | 直接返回实际记录数,用于监控数据量变化 | +| 数据准确性验证 | Diff | 计算实际值与期望值的绝对差值,适用于阈值比较 | +| 性能指标监控 | Percentage | 计算实际值相对于期望值的百分比,适用于比率分析 | +| 质量偏差分析 | Diff-Percentage | 计算偏差的相对大小,适用于敏感度分析 | +| 趋势变化检测 | ActualMinusExpectedDiff | 保留正负号的差值,用于分析变化方向 | + +选择公式时还需考虑以下因素: +- **精度要求**:所有公式都使用`BigDecimal`确保高精度计算 +- **性能影响**:简单公式(如Count)比复杂公式(如Diff-Percentage)执行更快 +- **业务语义**:选择能最好表达业务意图的公式 +- **可读性**:选择结果易于理解和解释的公式 + +**本节来源** +- [ResultFormula.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ResultFormula.java) +- 所有具体的公式实现类 + +## 性能优化建议 + +为了确保公式计算的高效性,建议采取以下优化措施: + +1. **缓存公式实例**:`PluginLoader`已经实现了公式类的缓存,避免重复实例化开销 +2. **批量计算**:对于大量数据的计算,应采用批量处理方式,减少函数调用开销 +3. **预编译公式**:对于复杂的公式逻辑,可以考虑预编译为可执行代码 +4. **并行计算**:独立的公式计算任务可以并行执行,充分利用多核CPU资源 +5. **精度控制**:根据业务需求合理设置`BigDecimal`的精度,避免不必要的高精度计算 + +```mermaid +flowchart TD +Start([性能优化起点]) --> Cache["缓存公式实例"] +Start --> Batch["批量数据处理"] +Start --> Parallel["并行计算任务"] +Start --> Precision["合理设置计算精度"] +Cache --> Optimize1["减少实例化开销"] +Batch --> Optimize2["降低I/O开销"] +Parallel --> Optimize3["提高CPU利用率"] +Precision --> Optimize4["减少计算复杂度"] +Optimize1 --> End([性能优化终点]) +Optimize2 --> End +Optimize3 --> End +Optimize4 --> End +``` + +**图示来源** +- [PluginLoader.java](file://datavines-spi\src\main\java\io\datavines\spi\PluginLoader.java) + +此外,应避免在循环中频繁创建`BigDecimal`对象,可以预先创建常用值的常量,如`BigDecimal.ZERO`和`BigDecimal.ONE`。 + +**本节来源** +- [PluginLoader.java](file://datavines-spi\src\main\java\io\datavines\spi\PluginLoader.java) +- 所有使用`BigDecimal`的公式实现类 + +## 复杂业务场景应用示例 + +在实际业务中,公式组合可以解决复杂的质量监控需求。例如,在电商交易数据监控中: + +```mermaid +flowchart TB +subgraph "数据采集" +A[原始交易数据] +end +subgraph "质量检查" +B[Count公式
统计交易总数] +C[ColumnNotNull公式
检查必填字段] +D[ColumnValueBetween公式
验证金额范围] +end +subgraph "结果计算" +E[Percentage公式
计算合规率] +F[Diff-Percentage公式
计算偏差率] +G[ActualMinusExpectedDiff公式
分析趋势变化] +end +subgraph "决策支持" +H[生成质量报告] +I[触发预警通知] +end +A --> B +A --> C +A --> D +B --> E +C --> E +D --> E +E --> F +E --> G +F --> H +G --> H +H --> I +``` + +**图示来源** +- 所有相关的公式实现类 + +另一个示例是金融风控场景中的复合指标计算: +1. 使用`Count`公式统计异常交易数量 +2. 使用`Percentage`公式计算异常交易占比 +3. 使用`Diff-Percentage`公式计算占比变化率 +4. 使用`ActualMinusExpectedDiff`公式判断变化方向 + +这种组合使用方式能够提供全面的风险视图,帮助决策者快速识别潜在问题。 + +**本节来源** +- 所有相关的公式实现类 + +## 结论 + +本文档详细介绍了数据质量监控系统中的结果计算公式体系。通过SPI扩展机制,系统实现了高度的可扩展性和灵活性。各种基础公式和复合公式满足了不同业务场景的需求,而合理的参数配置和组合使用方法则增强了系统的实用性。性能优化建议为大规模数据处理提供了指导。在实际应用中,应根据具体业务需求选择合适的公式,并充分利用组合能力来解决复杂的数据质量监控问题。 + +**本节不分析具体源文件,因此不提供来源** \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\345\233\272\345\256\232\345\200\274\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\345\233\272\345\256\232\345\200\274\347\255\226\347\225\245.md" new file mode 100644 index 00000000..583b90a1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\345\233\272\345\256\232\345\200\274\347\255\226\347\225\245.md" @@ -0,0 +1,155 @@ +# 固定值策略 + + +**本文档引用的文件** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) +- [index.tsx](file://datavines-ui\Editor\components\MetricModal\ExpectedValue\index.tsx) + + +## 目录 +1. [简介](#简介) +2. [核心实现原理](#核心实现原理) +3. [配置方式与数据类型支持](#配置方式与数据类型支持) +4. [验证机制](#验证机制) +5. [实际应用案例](#实际应用案例) +6. [性能特点与适用场景](#性能特点与适用场景) +7. [与其他策略的对比优势](#与其他策略的对比优势) + +## 简介 +固定值策略是数据质量校验中最基础且最直接的预期值策略之一。该策略通过预设一个固定的数值作为预期结果,用于与实际计算结果进行比较,从而判断数据质量是否达标。在DataVines系统中,`FixValue`类实现了这一策略,为用户提供了一种简单高效的基准值验证手段。 + +**Section sources** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) + +## 核心实现原理 +`FixValue`类实现了`ExpectedValue`接口,作为最简单的预期值策略,其核心逻辑在于不生成任何执行SQL或输出表,而是直接使用用户配置的固定值进行比较。该类通过返回`null`来表明不需要额外的数据源查询或计算过程,所有预期值信息都直接来源于用户输入参数。 + +```mermaid +classDiagram +class ExpectedValue { +<> ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +class FixValue { ++String getName() ++String getZhName() ++String getKey(Map inputParameter) ++String getExecuteSql(Map inputParameter) ++String getOutputTable(Map inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map config) +} +ExpectedValue <|.. FixValue : 实现 +``` + +**Diagram sources** +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) + +**Section sources** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) + +## 配置方式与数据类型支持 +固定值策略的配置非常直观,用户只需在数据质量规则中选择"固定值"作为预期值类型,并输入具体的数值即可。系统支持多种数据类型,包括数值型、字符串型、布尔型等。配置信息通过`expected_value`参数传递,并在作业配置构建时被正确处理和存储。 + +```mermaid +sequenceDiagram +participant UI as 用户界面 +participant Backend as 后端服务 +participant ConfigBuilder as 配置构建器 +UI->>Backend : 提交固定值配置 +Backend->>ConfigBuilder : 构建作业配置 +ConfigBuilder->>ConfigBuilder : 处理expected_value参数 +ConfigBuilder-->>Backend : 返回完整配置 +Backend-->>UI : 配置保存成功 +``` + +**Diagram sources** +- [index.tsx](file://datavines-ui\Editor\components\MetricModal\ExpectedValue\index.tsx) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) + +**Section sources** +- [index.tsx](file://datavines-ui\Editor\components\MetricModal\ExpectedValue\index.tsx) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) + +## 验证机制 +固定值策略的验证机制极为简洁高效。系统不会生成额外的SQL查询来获取预期值,而是直接使用用户配置的固定值与实际度量值进行比较。这种机制避免了不必要的数据库查询开销,提高了验证效率。验证过程由系统的比较运算符(如等于、大于、小于等)和阈值配置共同完成。 + +```mermaid +flowchart TD +Start([开始验证]) --> GetActualValue["获取实际度量值"] +GetActualValue --> GetExpectedValue["获取固定预期值"] +GetExpectedValue --> Compare["比较实际值与预期值"] +Compare --> IsValid{"是否满足条件?"} +IsValid --> |是| Pass["验证通过"] +IsValid --> |否| Fail["验证失败"] +Pass --> End([结束]) +Fail --> End +``` + +**Diagram sources** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) + +**Section sources** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) + +## 实际应用案例 +固定值策略广泛应用于各种数据质量校验场景。例如,在校验订单表的行数是否达到预期基准值时,可以设置固定值为10000,确保每日数据量不低于此阈值。另一个常见用例是枚举值校验,如订单状态字段只能是"待支付"、"已支付"、"已发货"等预定义值,通过固定值策略可以确保数据的完整性和一致性。 + +```mermaid +erDiagram +DATA_QUALITY_RULE ||--o{ EXPECTED_VALUE : "has" +DATA_QUALITY_RULE { +string rule_name +string metric_type +string operator +string threshold +} +EXPECTED_VALUE { +string expected_type "fix_value" +string expected_value +} +``` + +**Diagram sources** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) + +**Section sources** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) + +## 性能特点与适用场景 +固定值策略具有极佳的性能表现,因为它不需要额外的计算资源来确定预期值。适用于基准值验证、枚举值校验、数据完整性检查等场景。由于其简单直接的特性,特别适合用于实时性要求高、数据量大的校验任务。然而,对于需要动态计算预期值的复杂场景,如基于历史数据的平均值预测,则不适合使用固定值策略。 + +**Section sources** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) + +## 与其他策略的对比优势 +相较于其他动态预期值策略(如日均值、周均值等),固定值策略的最大优势在于其简单性和高效性。它不需要访问历史数据或执行复杂的计算逻辑,从而减少了系统开销和响应时间。此外,固定值策略的配置和理解成本极低,适合各类用户使用。虽然灵活性不如动态策略,但在明确知道预期结果的场景下,固定值策略是最优选择。 + +```mermaid +graph TD +A[预期值策略] --> B[固定值策略] +A --> C[动态值策略] +B --> D[优点: 简单、高效、低开销] +B --> E[缺点: 缺乏灵活性] +C --> F[优点: 灵活、适应性强] +C --> G[缺点: 复杂、高开销] +``` + +**Diagram sources** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java) + +**Section sources** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\345\221\250\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\345\221\250\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" new file mode 100644 index 00000000..c03aee3f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\345\221\250\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" @@ -0,0 +1,194 @@ +# 周平均值策略 + + +**本文档引用文件** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java) +- [SparkWeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkWeeklyAvg.java) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java) +- [FlinkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkMetricScript.java) +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) +- [CommonConstants.java](file://datavines-common\src\main\java\io\datavines\common\CommonConstants.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) +- [TimePlaceholderUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\placeholder\TimePlaceholderUtils.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 引言 +周平均值预期值策略是DataVines数据质量监控系统中的关键功能,用于计算指定指标在一周时间窗口内的平均值。该策略通过分析历史数据来建立基准值,为业务监控提供参考标准。本文档深入分析了`WeeklyAvg`和`SparkWeeklyAvg`类的实现机制,详细说明了周时间窗口处理逻辑、数据采样周期和Spark分布式计算优化。 + +## 核心组件 +周平均值策略的核心组件包括`WeeklyAvg`和`SparkWeeklyAvg`两个类,它们实现了`ExpectedValue`接口,负责计算一周内数据的平均值。`WeeklyAvg`作为通用实现,支持多种计算引擎,而`SparkWeeklyAvg`则专门针对Spark引擎进行了优化。 + +**本文档引用文件** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java) +- [SparkWeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkWeeklyAvg.java) + +## 架构概述 +周平均值策略的架构基于插件化设计,通过`ExpectedValue`接口定义了预期值计算的标准方法。系统根据配置的计算引擎类型(如Spark、Flink或本地)动态选择相应的实现类。`WeeklyAvg`类作为通用入口,根据`engine_type`参数调用不同引擎的`MetricScript`来生成具体的SQL查询。 + +```mermaid +graph TD +A[WeeklyAvg] --> B[getExecuteSql] +B --> C{engine_type} +C --> |spark| D[SparkMetricScript.weeklyAvg] +C --> |flink| E[FlinkMetricScript.weeklyAvg] +C --> |local| F[JdbcMetricScript.weeklyAvg] +D --> G[生成Spark SQL] +E --> H[生成Flink SQL] +F --> I[生成JDBC SQL] +``` + +**图表来源** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java#L44-L58) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java#L67-L71) +- [FlinkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkMetricScript.java#L69-L72) + +## 详细组件分析 + +### WeeklyAvg类分析 +`WeeklyAvg`类继承自`AbstractExpectedValue`,实现了`ExpectedValue`接口。它作为周平均值策略的通用实现,根据不同的计算引擎类型调用相应的`MetricScript`来生成SQL查询。 + +#### 类图 +```mermaid +classDiagram +class WeeklyAvg { ++getName() String ++getKey(Map) String ++getZhName() String ++getExecuteSql(Map) String ++getOutputTable(Map) String ++isNeedDefaultDatasource() boolean ++prepare(Map) void +} +class AbstractExpectedValue { ++getConnectorFactory(Map) ConnectorFactory ++getConnectorFactory(String) ConnectorFactory +} +class ExpectedValue { +<> ++getName() String ++getZhName() String ++getKey(Map) String ++getExecuteSql(Map) String ++getOutputTable(Map) String ++isNeedDefaultDatasource() boolean ++prepare(Map) void +} +WeeklyAvg --|> AbstractExpectedValue +AbstractExpectedValue ..> ExpectedValue +``` + +**图表来源** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java) +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) + +#### 执行流程 +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant WeeklyAvg as WeeklyAvg +participant ConnectorFactory as ConnectorFactory +participant MetricScript as MetricScript +用户->>WeeklyAvg : getExecuteSql(inputParameter) +WeeklyAvg->>WeeklyAvg : 获取engine_type +alt engine_type为spark或livy +WeeklyAvg->>ConnectorFactory : getConnectorFactory("spark") +ConnectorFactory-->>WeeklyAvg : SparkConnectorFactory +WeeklyAvg->>MetricScript : weeklyAvg(uniqueKey) +MetricScript-->>WeeklyAvg : Spark SQL +else engine_type为flink +WeeklyAvg->>ConnectorFactory : getConnectorFactory("flink") +ConnectorFactory-->>WeeklyAvg : FlinkConnectorFactory +WeeklyAvg->>MetricScript : weeklyAvg(uniqueKey) +MetricScript-->>WeeklyAvg : Flink SQL +else engine_type为local +WeeklyAvg->>ConnectorFactory : getConnectorFactory(inputParameter) +ConnectorFactory-->>WeeklyAvg : JdbcConnectorFactory +WeeklyAvg->>MetricScript : weeklyAvg(uniqueKey) +MetricScript-->>WeeklyAvg : JDBC SQL +else 其他类型 +WeeklyAvg-->>用户 : 抛出DataVinesException +end +WeeklyAvg-->>用户 : 返回SQL查询 +``` + +**图表来源** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java#L44-L58) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java#L67-L71) +- [FlinkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkMetricScript.java#L69-L72) + +### SparkWeeklyAvg类分析 +`SparkWeeklyAvg`类是专门为Spark引擎优化的周平均值实现,直接生成适用于Spark SQL的查询语句,避免了通过`ConnectorFactory`的间接调用,提高了执行效率。 + +#### 算法流程 +```mermaid +flowchart TD +Start([开始]) --> GetParams["获取参数: uniqueKey, data_time, unique_code"] +GetParams --> CalculateWeekStart["计算周开始时间: date_sub(date_format(${data_time},'yyyy-MM-dd'), (7- datediff(next_day(date_format(${data_time}, 'yyyy-MM-dd'),'Sunday'),date_format(${data_time}, 'yyyy-MM-dd')))-1)"] +CalculateWeekStart --> BuildSQL["构建SQL查询"] +BuildSQL --> ExecuteSQL["执行查询: select round(avg(actual_value),2) as expected_value_{uniqueKey} from dv_actual_values where data_time >= 周开始时间 and data_time < date_add(date_format(${data_time}, 'yyyy-MM-dd'),1) and unique_code = ${unique_code}"] +ExecuteSQL --> ReturnResult["返回结果"] +ReturnResult --> End([结束]) +``` + +**图表来源** +- [SparkWeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkWeeklyAvg.java#L44-L49) + +## 依赖分析 +周平均值策略的实现依赖于多个核心组件,包括`ExpectedValue`接口、`AbstractExpectedValue`基类、`ConnectorFactory`和各种`MetricScript`实现。这些组件通过SPI机制进行插件化管理,实现了良好的扩展性和灵活性。 + +```mermaid +graph TD +A[WeeklyAvg] --> B[AbstractExpectedValue] +B --> C[PluginLoader] +A --> D[DataVinesException] +A --> E[ConfigConstants] +F[SparkWeeklyAvg] --> G[ExpectedValue] +F --> E +H[SparkMetricScript] --> I[JdbcMetricScript] +I --> J[MetricScript接口] +``` + +**图表来源** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java) +- [SparkWeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkWeeklyAvg.java) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java) +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java) + +## 性能考虑 +周平均值策略在性能方面进行了多项优化: + +1. **分布式计算优化**:对于Spark引擎,直接生成优化的Spark SQL查询,充分利用分布式计算能力。 +2. **时间窗口计算优化**:使用Spark内置的日期函数高效计算周开始时间,避免了复杂的日期运算。 +3. **缓存机制**:通过`getConnectorFactory`的插件加载机制,实现了连接工厂的缓存,减少了重复创建的开销。 +4. **SQL生成优化**:预编译的SQL模板减少了运行时的字符串拼接开销。 + +在处理大规模数据时,建议使用Spark引擎以获得最佳性能。对于小规模数据或测试环境,可以使用本地引擎以简化部署。 + +## 故障排除指南 +### 常见问题及解决方案 + +| 问题描述 | 可能原因 | 解决方案 | +|---------|--------|---------| +| 查询执行失败 | 引擎类型不支持 | 检查`engine_type`配置,确保为`spark`、`flink`或`local`之一 | +| 结果不准确 | 时间窗口计算错误 | 验证`data_time`参数格式是否正确,应为`yyyy-MM-dd`格式 | +| 性能低下 | 数据量过大 | 考虑使用Spark引擎替代本地引擎,或优化数据分区策略 | +| 连接失败 | 数据源配置错误 | 检查默认数据源配置,确保`isNeedDefaultDatasource`返回`true` | + +**本文档引用文件** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java#L56-L57) +- [SparkWeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkWeeklyAvg.java#L58-L59) + +## 结论 +周平均值策略通过`WeeklyAvg`和`SparkWeeklyAvg`类的协同工作,实现了灵活且高效的周平均值计算功能。该策略支持多种计算引擎,能够适应不同的部署环境和性能需求。通过插件化设计和SPI机制,系统具有良好的扩展性,可以方便地添加新的计算引擎支持。在实际应用中,建议根据数据规模和性能要求选择合适的计算引擎,以获得最佳的监控效果。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\227\245\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\227\245\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" new file mode 100644 index 00000000..6ae8100c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\227\245\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" @@ -0,0 +1,145 @@ +# 日平均值策略 + + +**本文档引用的文件** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java) +- [SparkDailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\SparkDailyAvg.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java) +- [FlinkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkMetricScript.java) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) +- [io.datavines.metric.api.ExpectedValue](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\resources\META-INF\plugins\io.datavines.metric.api.ExpectedValue) + + +## 目录 +1. [简介](#简介) +2. [核心组件分析](#核心组件分析) +3. [时间窗口与数据聚合机制](#时间窗口与数据聚合机制) +4. [Spark执行计划解析](#spark执行计划解析) +5. [配置示例与应用场景](#配置示例与应用场景) +6. [数据延迟影响与应对策略](#数据延迟影响与应对策略) +7. [结论](#结论) + +## 简介 +日平均值预期值策略是数据质量监控系统中的关键组件,用于评估指定日期内数据指标的合理性。该策略通过计算历史数据的日平均值作为预期基准,与当日实际值进行对比,从而判断数据是否存在异常波动。本策略支持多种计算引擎(如Spark、Flink等),具备良好的扩展性和灵活性,广泛应用于每日订单量、用户活跃度等关键业务指标的监控场景。 + +## 核心组件分析 + +日平均值策略的核心实现由`DailyAvg`和`SparkDailyAvg`两个类构成,它们共同实现了`ExpectedValue`接口,遵循统一的预期值计算规范。 + +`DailyAvg`类继承自`AbstractExpectedValue`,作为通用的日均值计算实现,负责根据不同的执行引擎类型(spark、flink、local)动态调用相应的连接器工厂获取`MetricScript`,并执行对应的SQL脚本。该类通过`getExecuteSql`方法实现多引擎适配,确保在不同计算平台上的一致性行为。 + +`SparkDailyAvg`类则直接实现了`ExpectedValue`接口,专为Spark引擎优化,提供了特定的SQL生成逻辑。其`getExecuteSql`方法生成的SQL语句使用Spark SQL特有的日期函数(如`date_format`和`date_add`),确保在Spark环境下的高效执行。 + +两个类均实现了`getName`、`getZhName`、`getKey`、`getOutputTable`等核心方法,其中`getKey`方法生成用于标识预期值结果的唯一键,`getOutputTable`方法定义了输出结果的临时表名。 + +**本节来源** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L25-L75) +- [SparkDailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\SparkDailyAvg.java#L25-L66) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java#L24-L64) + +## 时间窗口与数据聚合机制 + +日平均值策略的时间窗口定义精确到天级别,其计算逻辑基于`data_time`字段进行筛选。对于指定的日期`${data_time}`,时间窗口的起始时间为当天的00:00:00,结束时间为次日的00:00:00(不包含),形成一个左闭右开的区间`[date_format(${data_time}, 'yyyy-MM-dd'), date_add(date_format(${data_time}, 'yyyy-MM-dd'),1))`。 + +数据聚合采用标准的`AVG()`函数对`actual_value`字段进行计算,并使用`ROUND()`函数将结果保留两位小数。计算过程从`dv_actual_values`表中提取历史数据,通过`unique_code`字段确保仅聚合与当前监控指标相关的数据。聚合结果以`expected_value_{uniqueKey}`为别名返回,便于后续的比较和分析。 + +该机制确保了每日计算的独立性和一致性,避免了跨日数据的干扰,为数据质量评估提供了可靠的基准。 + +```mermaid +flowchart TD +Start([开始计算日均值]) --> ExtractData["从 dv_actual_values 表提取数据"] +ExtractData --> FilterData["按时间窗口过滤: data_time >= 'YYYY-MM-DD' AND data_time < 'YYYY-MM-DD + 1'"] +FilterData --> FilterByUniqueCode["按 unique_code 过滤特定指标"] +FilterByUniqueCode --> CalculateAvg["计算平均值: ROUND(AVG(actual_value), 2)"] +CalculateAvg --> ReturnResult["返回结果: expected_value_{uniqueKey}"] +ReturnResult --> End([结束]) +``` + +**图表来源** +- [SparkDailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\SparkDailyAvg.java#L46-L48) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L129-L133) + +**本节来源** +- [SparkDailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\SparkDailyAvg.java#L44-L49) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java#L129-L133) + +## Spark执行计划解析 + +在Spark引擎环境下,日平均值策略的执行计划由`SparkDailyAvg`类和`SparkMetricScript`类协同完成。当系统检测到`engine_type`为`spark`或`livy`时,`DailyAvg`类会通过`getConnectorFactory("spark")`获取Spark连接器工厂,并调用其`getMetricScript()`方法获得`SparkMetricScript`实例。 + +`SparkMetricScript`继承自`JdbcMetricScript`,并重写了`dailyAvg`方法,生成适用于Spark SQL的查询语句。该SQL语句利用Spark内置的日期函数`date_format`和`date_add`来精确计算时间窗口边界。执行时,Spark会将此SQL作为任务提交到集群,通过分布式计算快速完成大规模历史数据的聚合分析。 + +执行计划的优化得益于Spark的Catalyst优化器,它会自动对查询进行解析、优化和代码生成,确保计算的高效性。同时,结果数据会被写入以`daily_range_{uniqueKey}`命名的临时表中,供后续的数据质量校验流程使用。 + +```mermaid +sequenceDiagram +participant 用户 as 用户/调度系统 +participant DailyAvg as DailyAvg类 +participant Factory as ConnectorFactory +participant Script as SparkMetricScript +participant Spark as Spark引擎 +participant DB as 数据库 +用户->>DailyAvg : 请求计算日均值 (engine_type=spark) +DailyAvg->>Factory : getConnectorFactory("spark") +Factory-->>DailyAvg : 返回Spark连接器工厂 +DailyAvg->>Script : getMetricScript().dailyAvg(uniqueKey) +Script-->>DailyAvg : 返回Spark SQL语句 +DailyAvg->>Spark : 提交SQL执行 +Spark->>DB : 执行查询 +DB-->>Spark : 返回聚合结果 +Spark-->>DailyAvg : 返回计算结果 +DailyAvg-->>用户 : 返回日均值预期值 +``` + +**图表来源** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L44-L50) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java#L39-L43) + +**本节来源** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L44-L57) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java#L39-L43) + +## 配置示例与应用场景 + +### 配置示例 +日平均值策略通过SPI机制进行注册和加载。在`META-INF/plugins/io.datavines.metric.api.ExpectedValue`文件中,定义了不同引擎类型对应的实现类: +``` +local_daily_avg=io.datavines.metric.expected.plugin.DailyAvg +spark_daily_avg=io.datavines.metric.expected.plugin.DailyAvg +livy_daily_avg=io.datavines.metric.expected.plugin.DailyAvg +flink_daily_avg=io.datavines.metric.expected.plugin.DailyAvg +``` +这表明无论使用何种引擎,系统最终都会加载`DailyAvg`类,并根据`engine_type`参数选择具体的SQL生成逻辑。 + +### 典型应用场景:每日订单量监控 +在电商数据质量监控中,日平均值策略常用于监控每日订单量。配置流程如下: +1. **定义指标**:创建一个监控指标,其实际值(actual value)为当日订单总数。 +2. **设置预期值策略**:选择“日均值”作为预期值策略。 +3. **配置执行引擎**:根据数据平台选择Spark或Flink作为计算引擎。 +4. **设定阈值**:配置允许的偏差范围,例如±10%。 + +系统将自动计算过去一段时间(如最近30天)的订单量日均值,并将其作为当日订单量的预期基准。如果当日订单量超出`预期值 ± 10%`的范围,系统将触发告警,提示数据异常,可能是由于数据采集故障、系统宕机或真实业务波动所致。 + +**本节来源** +- [io.datavines.metric.api.ExpectedValue](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\resources\META-INF\plugins\io.datavines.metric.api.ExpectedValue#L1-L4) +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L44-L57) + +## 数据延迟影响与应对策略 + +数据延迟是影响日平均值计算准确性的主要因素。由于数据从产生到入库存在一定的延迟,当日的`actual_value`可能在计算时并未完全写入`dv_actual_values`表,导致计算出的“日均值”实际上只包含了部分数据,从而产生偏差。 + +### 影响分析 +- **低估风险**:在数据延迟严重的场景下,当日聚合的`actual_value`不完整,导致计算出的平均值偏低。 +- **误报风险**:基于不完整数据计算的预期值会触发错误的告警,影响数据监控的可信度。 + +### 应对策略 +1. **延迟容忍机制**:在调度日平均值计算任务时,引入一个合理的延迟(如30分钟或1小时),等待大部分数据写入完成后再进行计算。 +2. **数据水位监控**:建立数据延迟监控体系,实时跟踪各数据源的延迟情况。当日均值计算任务启动前,先检查相关数据源的延迟是否在可接受范围内。 +3. **多次计算与修正**:对于关键指标,可以设计多次计算的机制。例如,首次计算在T+1小时进行,后续每隔一段时间重新计算一次,直到数据完全就绪,最终以最完整的那次计算结果为准。 +4. **使用事件时间**:在数据采集和处理环节,严格使用事件时间(Event Time)而非处理时间(Processing Time),确保数据按其真实发生时间进行归集和计算。 + +通过以上策略,可以有效缓解数据延迟带来的负面影响,确保日平均值预期值的准确性和可靠性。 + +## 结论 +日平均值预期值策略通过`DailyAvg`和`SparkDailyAvg`等核心类的协同工作,实现了跨引擎的、高效的数据质量监控能力。其基于精确的时间窗口和标准的聚合函数,为业务指标提供了可靠的基准。该策略在Spark等分布式计算引擎上的良好集成,使其能够处理海量历史数据。尽管面临数据延迟的挑战,但通过合理的调度和监控策略,可以有效保障计算结果的准确性。该策略在每日订单量、用户活跃度等场景中具有广泛的应用价值,是构建健壮数据质量体系的重要组成部分。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" new file mode 100644 index 00000000..863b6717 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" @@ -0,0 +1,338 @@ +# 时间序列平均值策略 + + +**本文档引用的文件** +- [DailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) +- [SparkDailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/SparkDailyAvg.java) +- [SparkLast7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/SparkLast7DayAvg.java) +- [SparkLast30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/SparkLast30DayAvg.java) +- [SparkWeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/SparkWeeklyAvg.java) +- [SparkMonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/SparkMonthlyAvg.java) +- [ExpectedValue.java](file://datavines-metric/metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ConnectorFactory.java](file://datavines-connector/connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录)(如有必要) + +## 引言 +本文档详细介绍了DataVines平台中时间序列平均值预期值策略的实现机制。重点分析了DailyAvg、Last7DayAvg、Last30DayAvg、WeeklyAvg和MonthlyAvg等策略的计算逻辑和时间窗口处理机制。文档解释了这些策略如何通过Spark引擎执行历史数据聚合计算,详细说明了各策略的配置参数、时间范围定义和数据采样方法。同时,提供了不同时间粒度预期值在业务监控中的应用案例,并讨论了数据延迟和窗口对齐对计算结果的影响。 + +## 项目结构 +DataVines平台的项目结构清晰地组织了各种预期值策略的实现。所有时间序列平均值策略都位于`datavines-metric-expected-plugins`模块中,每个策略都有独立的子模块。这种模块化设计使得策略的扩展和维护更加容易。 + +```mermaid +graph TD +A[datavines-metric-expected-plugins] --> B[datavines-metric-expected-daily-avg] +A --> C[datavines-metric-expected-last7day-avg] +A --> D[datavines-metric-expected-last30day-avg] +A --> E[datavines-metric-expected-weekly-avg] +A --> F[datavines-metric-expected-monthly-avg] +B --> G[DailyAvg.java] +B --> H[SparkDailyAvg.java] +C --> I[Last7DayAvg.java] +C --> J[SparkLast7DayAvg.java] +D --> K[Last30DayAvg.java] +D --> L[SparkLast30DayAvg.java] +E --> M[WeeklyAvg.java] +E --> N[SparkWeeklyAvg.java] +F --> O[MonthlyAvg.java] +F --> P[SparkMonthlyAvg.java] +``` + +**图表来源** +- [DailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) + +**章节来源** +- [DailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) + +## 核心组件 +时间序列平均值策略的核心组件包括各种预期值计算策略的实现类,如DailyAvg、Last7DayAvg、Last30DayAvg、WeeklyAvg和MonthlyAvg。这些组件都实现了ExpectedValue接口,提供了统一的API来获取策略名称、执行SQL和输出表名等信息。每个策略都有对应的Spark引擎实现类,用于生成特定于Spark的执行SQL。 + +**章节来源** +- [DailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) + +## 架构概述 +时间序列平均值策略的架构基于插件化设计模式,通过SPI(Service Provider Interface)机制实现策略的动态加载。系统通过ConnectorFactory获取相应的MetricScript来生成执行SQL,然后由Spark引擎执行这些SQL来计算预期值。 + +```mermaid +graph TD +A[用户请求] --> B{策略选择} +B --> C[DailyAvg] +B --> D[Last7DayAvg] +B --> E[Last30DayAvg] +B --> F[WeeklyAvg] +B --> G[MonthlyAvg] +C --> H[SparkDailyAvg] +D --> I[SparkLast7DayAvg] +E --> J[SparkLast30DayAvg] +F --> K[SparkWeeklyAvg] +G --> L[SparkMonthlyAvg] +H --> M[Spark引擎] +I --> M +J --> M +K --> M +L --> M +M --> N[计算结果] +``` + +**图表来源** +- [DailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) +- [SparkDailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/SparkDailyAvg.java) +- [SparkLast7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/SparkLast7DayAvg.java) +- [SparkLast30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/SparkLast30DayAvg.java) +- [SparkWeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/SparkWeeklyAvg.java) +- [SparkMonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/SparkMonthlyAvg.java) + +## 详细组件分析 +### DailyAvg策略分析 +DailyAvg策略用于计算每日平均值,其时间窗口为当前日期的00:00:00到23:59:59。该策略通过Spark引擎执行SQL查询来计算预期值。 + +```mermaid +classDiagram +class DailyAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +class SparkDailyAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +DailyAvg <|-- SparkDailyAvg : 实现 +``` + +**图表来源** +- [DailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [SparkDailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/SparkDailyAvg.java) + +### Last7DayAvg策略分析 +Last7DayAvg策略用于计算最近7天的平均值,其时间窗口为当前日期往前推7天到当前日期。该策略同样通过Spark引擎执行SQL查询来计算预期值。 + +```mermaid +classDiagram +class Last7DayAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +class SparkLast7DayAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +Last7DayAvg <|-- SparkLast7DayAvg : 实现 +``` + +**图表来源** +- [Last7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [SparkLast7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/SparkLast7DayAvg.java) + +### Last30DayAvg策略分析 +Last30DayAvg策略用于计算最近30天的平均值,其时间窗口为当前日期往前推30天到当前日期。该策略通过Spark引擎执行SQL查询来计算预期值。 + +```mermaid +classDiagram +class Last30DayAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +class SparkLast30DayAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +Last30DayAvg <|-- SparkLast30DayAvg : 实现 +``` + +**图表来源** +- [Last30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [SparkLast30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/SparkLast30DayAvg.java) + +### WeeklyAvg策略分析 +WeeklyAvg策略用于计算周平均值,其时间窗口为当前周的周一到周日。该策略通过Spark引擎执行SQL查询来计算预期值。 + +```mermaid +classDiagram +class WeeklyAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +class SparkWeeklyAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +WeeklyAvg <|-- SparkWeeklyAvg : 实现 +``` + +**图表来源** +- [WeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [SparkWeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/SparkWeeklyAvg.java) + +### MonthlyAvg策略分析 +MonthlyAvg策略用于计算月平均值,其时间窗口为当前月的第一天到最后一天。该策略通过Spark引擎执行SQL查询来计算预期值。 + +```mermaid +classDiagram +class MonthlyAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +class SparkMonthlyAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +MonthlyAvg <|-- SparkMonthlyAvg : 实现 +``` + +**图表来源** +- [MonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) +- [SparkMonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/SparkMonthlyAvg.java) + +**章节来源** +- [DailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) +- [SparkDailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/SparkDailyAvg.java) +- [SparkLast7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/SparkLast7DayAvg.java) +- [SparkLast30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/SparkLast30DayAvg.java) +- [SparkWeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/SparkWeeklyAvg.java) +- [SparkMonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/SparkMonthlyAvg.java) + +## 依赖分析 +时间序列平均值策略依赖于ExpectedValue接口和ConnectorFactory接口。ExpectedValue接口定义了策略的基本行为,而ConnectorFactory接口提供了获取MetricScript的能力,用于生成执行SQL。 + +```mermaid +graph TD +A[ExpectedValue] --> B[DailyAvg] +A --> C[Last7DayAvg] +A --> D[Last30DayAvg] +A --> E[WeeklyAvg] +A --> F[MonthlyAvg] +G[ConnectorFactory] --> H[MetricScript] +H --> I[SparkDailyAvg] +H --> J[SparkLast7DayAvg] +H --> K[SparkLast30DayAvg] +H --> L[SparkWeeklyAvg] +H --> M[SparkMonthlyAvg] +``` + +**图表来源** +- [ExpectedValue.java](file://datavines-metric/metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ConnectorFactory.java](file://datavines-connector/connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +**章节来源** +- [ExpectedValue.java](file://datavines-metric/metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [ConnectorFactory.java](file://datavines-connector/connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java) + +## 性能考虑 +在执行时间序列平均值计算时,需要考虑以下几个性能因素: +1. 数据量:历史数据量越大,计算时间越长。 +2. 窗口大小:时间窗口越大,需要处理的数据越多,计算时间越长。 +3. 查询优化:通过合理的索引和分区策略可以提高查询性能。 +4. 资源分配:合理分配Spark集群资源可以提高计算效率。 + +## 故障排除指南 +在使用时间序列平均值策略时,可能会遇到以下问题: +1. 数据延迟:由于数据延迟,可能导致计算结果不准确。 +2. 窗口对齐:时间窗口的对齐方式可能影响计算结果。 +3. SQL语法错误:生成的SQL可能存在语法错误,需要检查。 +4. 资源不足:Spark集群资源不足可能导致计算失败。 + +**章节来源** +- [DailyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-daily-avg/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last7day-avg/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-last30day-avg/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java) +- [WeeklyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-weekly-avg/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java) +- [MonthlyAvg.java](file://datavines-metric/expected-plugins/datavines-metric-expected-monthly-avg/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java) + +## 结论 +本文档详细介绍了DataVines平台中时间序列平均值预期值策略的实现机制。通过分析DailyAvg、Last7DayAvg、Last30DayAvg、WeeklyAvg和MonthlyAvg等策略的计算逻辑和时间窗口处理机制,我们可以更好地理解这些策略在业务监控中的应用。同时,文档还讨论了数据延迟和窗口对齐对计算结果的影响,为实际应用提供了有价值的参考。 + +## 附录 +### 配置参数说明 +- **engine_type**: 指定使用的计算引擎类型,如spark、flink或local。 +- **src_connector_type**: 指定数据源连接器类型。 +- **METRIC_UNIQUE_KEY**: 指定指标的唯一键,用于生成输出表名和SQL查询。 + +### 应用案例 +1. **日均交易量监控**: 使用DailyAvg策略监控每日交易量,及时发现异常波动。 +2. **周同比波动分析**: 使用Last7DayAvg策略分析周同比波动,评估业务趋势。 +3. **月度业绩评估**: 使用MonthlyAvg策略评估月度业绩,为决策提供数据支持。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\234\200\350\277\221N\345\244\251\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\234\200\350\277\221N\345\244\251\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" new file mode 100644 index 00000000..b6c618bb --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\234\200\350\277\221N\345\244\251\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" @@ -0,0 +1,314 @@ +# 最近N天平均值策略 + + +**本文档引用的文件** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java) +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java) +- [SparkLast30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast30DayAvg.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql) + + +## 目录 +1. [引言](#引言) +2. [核心组件分析](#核心组件分析) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [滑动时间窗口处理机制](#滑动时间窗口处理机制) +6. [配置方法与性能优化](#配置方法与性能优化) +7. [应用案例](#应用案例) +8. [数据新鲜度与监控效果](#数据新鲜度与监控效果) +9. [结论](#结论) + +## 引言 +最近N天平均值预期值策略是数据质量监控系统中的核心功能之一,用于评估当前数据指标与历史数据趋势的偏离程度。该策略通过计算最近7天或30天的历史平均值,作为当前数据的预期值,从而判断数据是否存在异常波动。本文档将深入分析Last7DayAvg、Last30DayAvg及其Spark实现类的计算逻辑,解释滑动时间窗口的处理机制,详细说明不同时间跨度的配置方法、性能优化策略和历史数据查询优化。 + +## 核心组件分析 + +最近N天平均值策略的核心组件包括`Last7DayAvg`、`Last30DayAvg`及其对应的Spark实现类`SparkLast7DayAvg`和`SparkLast30DayAvg`。这些类实现了`ExpectedValue`接口,提供了计算预期值所需的方法。 + +**组件关系** +```mermaid +classDiagram +class ExpectedValue { +<> ++getName() String ++getZhName() String ++getKey(Map) String ++getExecuteSql(Map) String ++getOutputTable(Map) String ++isNeedDefaultDatasource() boolean ++prepare(Map) void +} +class AbstractExpectedValue { ++getConnectorFactory(Map) ConnectorFactory ++getConnectorFactory(String) ConnectorFactory +} +class Last7DayAvg { ++getName() String ++getZhName() String ++getKey(Map) String ++getExecuteSql(Map) String ++getOutputTable(Map) String ++isNeedDefaultDatasource() boolean ++prepare(Map) void +} +class Last30DayAvg { ++getName() String ++getZhName() String ++getKey(Map) String ++getExecuteSql(Map) String ++getOutputTable(Map) String ++isNeedDefaultDatasource() boolean ++prepare(Map) void +} +class SparkLast7DayAvg { ++getName() String ++getZhName() String ++getKey(Map) String ++getExecuteSql(Map) String ++getOutputTable(Map) String ++isNeedDefaultDatasource() boolean ++prepare(Map) void +} +class SparkLast30DayAvg { ++getName() String ++getZhName() String ++getKey(Map) String ++getExecuteSql(Map) String ++getOutputTable(Map) String ++isNeedDefaultDatasource() boolean ++prepare(Map) void +} +ExpectedValue <|-- AbstractExpectedValue : "继承" +AbstractExpectedValue <|-- Last7DayAvg : "继承" +AbstractExpectedValue <|-- Last30DayAvg : "继承" +ExpectedValue <|-- SparkLast7DayAvg : "实现" +ExpectedValue <|-- SparkLast30DayAvg : "实现" +Last7DayAvg --> SparkLast7DayAvg : "使用" +Last30DayAvg --> SparkLast30DayAvg : "使用" +``` + +**图表来源** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java) +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java) +- [SparkLast30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast30DayAvg.java) + +**章节来源** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java) + +## 架构概述 + +最近N天平均值策略的架构设计遵循了插件化和可扩展的原则。系统通过`ExpectedValue`接口定义了预期值计算的标准方法,不同的时间跨度(如7天、30天)通过实现该接口来提供具体的计算逻辑。对于不同的执行引擎(如Spark、Flink、Local),系统提供了相应的实现类来生成特定于引擎的SQL语句。 + +**系统架构图** +```mermaid +graph TD +subgraph "前端" +UI[用户界面] +end +subgraph "后端" +API[API服务] +JobScheduler[作业调度器] +EngineExecutor[引擎执行器] +ExpectedValue[预期值计算] +end +subgraph "数据存储" +MySQL[MySQL数据库] +Spark[Spark集群] +end +UI --> API +API --> JobScheduler +JobScheduler --> EngineExecutor +EngineExecutor --> ExpectedValue +ExpectedValue --> MySQL +ExpectedValue --> Spark +MySQL --> ExpectedValue +Spark --> ExpectedValue +``` + +**图表来源** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql) + +**章节来源** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java) + +## 详细组件分析 + +### Last7DayAvg 分析 +`Last7DayAvg`类是最近7天平均值策略的核心实现,它继承自`AbstractExpectedValue`类,实现了`ExpectedValue`接口。该类的主要职责是根据配置参数生成相应的SQL查询语句,用于计算最近7天的平均值。 + +**关键方法分析** +- `getName()`: 返回策略的英文名称"last_7d_avg"。 +- `getZhName()`: 返回策略的中文名称"最近7天均值"。 +- `getKey(Map inputParameter)`: 生成用于标识预期值的键,格式为"expected_value_{uniqueKey}"。 +- `getExecuteSql(Map inputParameter)`: 根据执行引擎类型(Spark、Flink、Local)调用相应的`MetricScript`生成SQL查询语句。 +- `getOutputTable(Map inputParameter)`: 返回输出表的名称,格式为"last_7d_{uniqueKey}"。 +- `isNeedDefaultDatasource()`: 返回true,表示需要默认的数据源。 + +**章节来源** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java) + +### SparkLast7DayAvg 分析 +`SparkLast7DayAvg`类是针对Spark执行引擎的最近7天平均值策略实现。它直接实现了`ExpectedValue`接口,提供了针对Spark的SQL生成逻辑。 + +**关键方法分析** +- `getName()`: 返回策略的英文名称"last_7d_avg"。 +- `getZhName()`: 返回策略的中文名称"最近7天均值"。 +- `getKey(Map inputParameter)`: 生成用于标识预期值的键,格式为"last_7d_{uniqueKey}.expected_value_{uniqueKey}"。 +- `getExecuteSql(Map inputParameter)`: 生成计算最近7天平均值的SQL查询语句,使用`date_add`函数计算时间范围。 +- `getOutputTable(Map inputParameter)`: 返回输出表的名称,格式为"last_7d_{uniqueKey}"。 +- `isNeedDefaultDatasource()`: 返回true,表示需要默认的数据源。 + +**章节来源** +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java) + +### Last30DayAvg 分析 +`Last30DayAvg`类是最近30天平均值策略的核心实现,其结构和功能与`Last7DayAvg`类似,但时间跨度为30天。 + +**关键方法分析** +- `getName()`: 返回策略的英文名称"last_30d_avg"。 +- `getZhName()`: 返回策略的中文名称"最近30天均值"。 +- `getKey(Map inputParameter)`: 生成用于标识预期值的键,格式为"expected_value_{uniqueKey}"。 +- `getExecuteSql(Map inputParameter)`: 根据执行引擎类型调用相应的`MetricScript`生成SQL查询语句。 +- `getOutputTable(Map inputParameter)`: 返回输出表的名称,格式为"last_30d_{uniqueKey}"。 +- `isNeedDefaultDatasource()`: 返回true,表示需要默认的数据源。 + +**章节来源** +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java) + +### SparkLast30DayAvg 分析 +`SparkLast30DayAvg`类是针对Spark执行引擎的最近30天平均值策略实现,其结构和功能与`SparkLast7DayAvg`类似,但时间跨度为30天。 + +**关键方法分析** +- `getName()`: 返回策略的英文名称"last_30d_avg"。 +- `getZhName()`: 返回策略的中文名称"最近30天均值"。 +- `getKey(Map inputParameter)`: 生成用于标识预期值的键,格式为"last_30d_{uniqueKey}.expected_value_{uniqueKey}"。 +- `getExecuteSql(Map inputParameter)`: 生成计算最近30天平均值的SQL查询语句,使用`date_add`函数计算时间范围。 +- `getOutputTable(Map inputParameter)`: 返回输出表的名称,格式为"last_30d_{uniqueKey}"。 +- `isNeedDefaultDatasource()`: 返回true,表示需要默认的数据源。 + +**章节来源** +- [SparkLast30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast30DayAvg.java) + +## 滑动时间窗口处理机制 + +最近N天平均值策略的核心是滑动时间窗口的处理机制。系统通过SQL查询语句中的时间函数来实现滑动窗口,确保每次计算都能获取到最新的历史数据。 + +**SQL查询逻辑** +```sql +-- 最近7天平均值查询 +select round(avg(actual_value),2) as expected_value_{uniqueKey} +from dv_actual_values +where data_time >= date_add(date_format(${data_time}, 'yyyy-MM-dd'),-7) + and data_time < date_add(date_format(${data_time}, 'yyyy-MM-dd'),1) + and unique_code = ${unique_code} + +-- 最近30天平均值查询 +select round(avg(actual_value),2) as expected_value_{uniqueKey} +from dv_actual_values +where data_time >= date_add(date_format(${data_time}, 'yyyy-MM-dd'),-30) + and data_time < date_add(date_format(${data_time}, 'yyyy-MM-dd'),1) + and unique_code = ${unique_code} +``` + +**处理流程** +1. 系统接收到计算预期值的请求。 +2. 根据配置参数确定时间跨度(7天或30天)和执行引擎类型。 +3. 调用相应的`ExpectedValue`实现类生成SQL查询语句。 +4. 执行SQL查询,从`dv_actual_values`表中获取指定时间范围内的历史数据。 +5. 计算平均值并返回结果。 + +**图表来源** +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java) +- [SparkLast30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast30DayAvg.java) +- [MetricScript.java](file://datavines-connector\datavines-connector-api\src\main\java\io\datavines\connector\api\MetricScript.java) + +**章节来源** +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java) +- [SparkLast30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast30DayAvg.java) + +## 配置方法与性能优化 + +### 配置方法 +最近N天平均值策略的配置主要通过`inputParameter`参数进行,关键配置项包括: +- `METRIC_UNIQUE_KEY`: 指标唯一键,用于标识不同的监控指标。 +- `engine_type`: 执行引擎类型,支持Spark、Flink、Local等。 + +**配置示例** +```json +{ + "METRIC_UNIQUE_KEY": "web_traffic_001", + "engine_type": "spark" +} +``` + +### 性能优化策略 +1. **索引优化**: 在`dv_actual_values`表的`data_time`和`unique_code`字段上创建复合索引,提高查询效率。 +2. **分区表**: 按照`data_time`字段对`dv_actual_values`表进行分区,减少查询时的数据扫描量。 +3. **缓存机制**: 对频繁查询的预期值结果进行缓存,避免重复计算。 +4. **并行处理**: 利用Spark的分布式计算能力,对大规模数据进行并行处理。 + +### 历史数据查询优化 +1. **预计算**: 定期预计算常用时间跨度的平均值,存储在专门的汇总表中。 +2. **增量更新**: 只查询新增的数据,基于之前的计算结果进行增量更新。 +3. **数据压缩**: 对历史数据进行压缩存储,减少存储空间和I/O开销。 + +**章节来源** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql) + +## 应用案例 + +### 最近7天网站访问量监控 +在网站访问量监控场景中,可以使用最近7天平均值策略来检测访问量的异常波动。 + +**监控流程** +1. 每天收集网站的访问量数据,存储在`dv_actual_values`表中。 +2. 使用`Last7DayAvg`策略计算最近7天的平均访问量。 +3. 将当天的访问量与7天平均值进行比较,判断是否存在异常。 +4. 如果偏差超过预设阈值,触发告警。 + +**SQL查询示例** +```sql +-- 计算最近7天平均访问量 +select round(avg(actual_value),2) as expected_value_web_traffic +from dv_actual_values +where data_time >= date_add(date_format('2024-01-15', 'yyyy-MM-dd'),-7) + and data_time < date_add(date_format('2024-01-15', 'yyyy-MM-dd'),1) + and unique_code = 'web_traffic_001' +``` + +**图表来源** +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql) + +**章节来源** +- [SparkLast7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\SparkLast7DayAvg.java) + +## 数据新鲜度与监控效果 + +### 数据新鲜度 +数据新鲜度是指数据的时效性,对于最近N天平均值策略而言,数据新鲜度直接影响监控的准确性。系统通过`data_time`字段来标识数据的时间戳,确保计算时使用的是最新的数据。 + +### 窗口滑动频率 +窗口滑动频率决定了监控的粒度和响应速度。较高的滑动频率(如每小时)可以提供更及时的监控,但会增加计算开销;较低的滑动频率(如每天)则计算开销较小,但可能错过短期的异常波动。 + +### 监控效果影响 +1. **高频率滑动**: 能够快速发现数据异常,适合对实时性要求高的场景。 +2. **低频率滑动**: 计算资源消耗较少,适合对实时性要求不高的场景。 +3. **数据延迟**: 如果数据采集存在延迟,可能导致计算结果不准确,需要考虑数据延迟的容忍度。 + +**章节来源** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java) + +## 结论 +最近N天平均值预期值策略通过计算历史数据的平均值来评估当前数据的合理性,是数据质量监控系统中的重要组成部分。通过对`Last7DayAvg`、`Last30DayAvg`及其Spark实现类的深入分析,我们了解了其计算逻辑和滑动时间窗口的处理机制。通过合理的配置方法和性能优化策略,可以有效提高监控的准确性和效率。在实际应用中,需要根据具体场景选择合适的时间跨度和滑动频率,以达到最佳的监控效果。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\234\210\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\234\210\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" new file mode 100644 index 00000000..287e9b2f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\346\227\266\351\227\264\345\272\217\345\210\227\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245/\346\234\210\345\271\263\345\235\207\345\200\274\347\255\226\347\225\245.md" @@ -0,0 +1,295 @@ +# 月平均值策略 + + +**本文档引用的文件** +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java) +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java) +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java) +- [FlinkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkMetricScript.java) +- [ActualValues.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\ActualValues.java) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql) + + +## 目录 +1. [引言](#引言) +2. [核心组件分析](#核心组件分析) +3. [月平均值计算原理](#月平均值计算原理) +4. [时间窗口与边界处理](#时间窗口与边界处理) +5. [大规模数据聚合优化](#大规模数据聚合优化) +6. [配置示例与应用案例](#配置示例与应用案例) +7. [特殊日期影响分析](#特殊日期影响分析) +8. [结论](#结论) + +## 引言 + +月平均值策略是数据质量监控系统中的重要组成部分,用于计算指定指标在一个月内的平均值。该策略通过分析历史数据,为当前数据提供预期值参考,广泛应用于财务指标监控、业务绩效评估等场景。本文档深入分析MonthlyAvg和SparkMonthlyAvg类的实现原理,详细说明月度时间窗口定义、月末边界处理和大规模数据聚合优化技术。 + +## 核心组件分析 + +月平均值策略的核心实现由MonthlyAvg和SparkMonthlyAvg两个类构成,它们共同实现了基于不同计算引擎的月均值计算功能。MonthlyAvg作为主入口类,负责根据配置选择合适的计算引擎,而SparkMonthlyAvg则专注于Spark引擎下的具体实现。 + +```mermaid +classDiagram +class ExpectedValue { +<> ++String getName() ++String getZhName() ++String getKey(Map~String,String~ inputParameter) ++String getExecuteSql(Map~String,String~ inputParameter) ++String getOutputTable(Map~String,String~ inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map~String,String~ config) +} +class AbstractExpectedValue { ++ConnectorFactory getConnectorFactory(Map~String,String~ inputParameter) ++ConnectorFactory getConnectorFactory(String connectorType) +} +class MonthlyAvg { ++String getName() ++String getZhName() ++String getKey(Map~String,String~ inputParameter) ++String getExecuteSql(Map~String,String~ inputParameter) ++String getOutputTable(Map~String,String~ inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map~String,String~ config) +} +class SparkMonthlyAvg { ++String getName() ++String getZhName() ++String getKey(Map~String,String~ inputParameter) ++String getExecuteSql(Map~String,String~ inputParameter) ++String getOutputTable(Map~String,String~ inputParameter) ++boolean isNeedDefaultDatasource() ++void prepare(Map~String,String~ config) +} +ExpectedValue <|-- AbstractExpectedValue +AbstractExpectedValue <|-- MonthlyAvg +ExpectedValue <|-- SparkMonthlyAvg +MonthlyAvg --> SparkMonthlyAvg : "委托" +``` + +**图表来源** +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java) +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java) +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java) + +**本节来源** +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java#L24-L74) +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java#L25-L66) + +## 月平均值计算原理 + +月平均值策略的计算原理基于对历史数据的聚合分析。系统通过查询`dv_actual_values`表中指定时间范围内的实际值,计算其算术平均数作为预期值。计算过程遵循以下步骤: + +1. 确定当前数据的时间戳(data_time) +2. 计算该时间戳所在月份的第一天 +3. 查询从该月第一天到当前时间点的所有历史数据 +4. 对查询到的实际值进行平均值计算 +5. 将结果四舍五入到两位小数 + +```mermaid +flowchart TD +Start([开始]) --> GetDataTime["获取当前数据时间戳"] +GetDataTime --> CalculateMonthStart["计算月份起始日期"] +CalculateMonthStart --> QueryData["查询历史数据"] +QueryData --> CalculateAvg["计算平均值"] +CalculateAvg --> RoundResult["四舍五入到两位小数"] +RoundResult --> ReturnResult["返回预期值"] +ReturnResult --> End([结束]) +``` + +**图表来源** +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java#L44-L48) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java#L60-L64) + +**本节来源** +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java#L44-L48) +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java#L43-L56) + +## 时间窗口与边界处理 + +月平均值策略的时间窗口定义和边界处理是确保计算准确性的关键。系统采用不同的SQL语法来处理不同计算引擎的时间窗口,确保在各种环境下都能正确计算月度平均值。 + +### Spark引擎时间窗口 + +在Spark引擎下,时间窗口的定义使用Hive SQL的日期函数: +- 起始时间:`date_format(${data_time}, 'yyyy-MM-01')`,将日期格式化为当月第一天 +- 结束时间:`date_add(date_format(${data_time}, 'yyyy-MM-dd'),1)`,将当前日期加一天 + +这种处理方式确保了时间窗口包含整个当月的所有数据,从当月第一天开始,到下月第一天结束。 + +### Flink引擎时间窗口 + +在Flink引擎下,时间窗口的定义使用参数化的方式: +- 起始时间:`${month_start_day} 00:00:00`,使用预计算的月份开始日期 +- 结束时间:`${month_end_day} 23:59:59`,使用预计算的月份结束日期 + +```mermaid +sequenceDiagram +participant User as "用户" +participant MonthlyAvg as "MonthlyAvg" +participant SparkMonthlyAvg as "SparkMonthlyAvg" +participant Database as "数据库" +User->>MonthlyAvg : 请求月平均值 +MonthlyAvg->>MonthlyAvg : 获取引擎类型 +MonthlyAvg->>MonthlyAvg : 选择计算实现 +alt Spark引擎 +MonthlyAvg->>SparkMonthlyAvg : 委托计算 +SparkMonthlyAvg->>Database : 执行SQL查询 +Database-->>SparkMonthlyAvg : 返回结果 +SparkMonthlyAvg-->>MonthlyAvg : 返回预期值 +else Flink引擎 +MonthlyAvg->>FlinkMetricScript : 调用Flink实现 +FlinkMetricScript->>Database : 执行SQL查询 +Database-->>FlinkMetricScript : 返回结果 +FlinkMetricScript-->>MonthlyAvg : 返回预期值 +end +MonthlyAvg-->>User : 返回月平均值 +``` + +**图表来源** +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java#L44-L48) +- [FlinkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkMetricScript.java#L62-L65) +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java#L43-L56) + +**本节来源** +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java#L44-L48) +- [FlinkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkMetricScript.java#L62-L65) + +## 大规模数据聚合优化 + +为应对大规模数据聚合的性能挑战,月平均值策略采用了多项优化技术,确保在海量数据环境下仍能高效计算。 + +### 引擎适配优化 + +系统通过MonthlyAvg类的`getExecuteSql`方法实现了引擎适配机制。该方法根据配置的引擎类型(spark、flink、local)动态选择最优的SQL实现: + +```mermaid +flowchart TD +Start([开始]) --> GetEngineType["获取引擎类型"] +GetEngineType --> CheckEngine["判断引擎类型"] +CheckEngine --> |Spark| UseSparkSQL["使用Spark SQL实现"] +CheckEngine --> |Flink| UseFlinkSQL["使用Flink SQL实现"] +CheckEngine --> |Local| UseLocalSQL["使用本地SQL实现"] +CheckEngine --> |其他| ThrowException["抛出异常"] +UseSparkSQL --> ExecuteQuery["执行查询"] +UseFlinkSQL --> ExecuteQuery +UseLocalSQL --> ExecuteQuery +ExecuteQuery --> ReturnResult["返回结果"] +ThrowException --> ReturnError["返回错误"] +ReturnResult --> End([结束]) +ReturnError --> End +``` + +### 数据表结构优化 + +实际值存储表`dv_actual_values`经过专门设计,以支持高效的聚合查询: + +```mermaid +erDiagram +dv_actual_values { +bigint id PK +bigint job_execution_id +varchar metric_name +varchar unique_code +double actual_value +datetime data_time +datetime create_time +datetime update_time +} +dv_actual_values ||--o{ dv_job_execution : "执行关联" +dv_actual_values }|--|| dv_metric_definition : "指标关联" +``` + +表结构特点: +- `data_time`字段用于时间范围查询,支持高效的索引扫描 +- `unique_code`字段用于区分不同指标实例,支持多指标并行计算 +- `actual_value`字段存储双精度浮点数,保证计算精度 + +**图表来源** +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java#L43-L56) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql#L166-L168) +- [ActualValues.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\ActualValues.java#L31) + +**本节来源** +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java#L43-L56) +- [SparkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-spark\src\main\java\io\datavines\connector\plugin\SparkMetricScript.java#L60-L64) + +## 配置示例与应用案例 + +### 配置示例 + +```json +{ + "engine_type": "spark", + "src_connector_type": "jdbc", + "metric_unique_key": "monthly_sales_avg", + "data_time": "2024-03-15 10:30:00", + "unique_code": "sales_metric_001" +} +``` + +### 财务指标监控应用案例 + +在月度销售额分析场景中,系统使用月平均值策略来监控销售业绩: + +```mermaid +flowchart LR +A[每日销售额数据] --> B[存储到dv_actual_values] +B --> C[月度监控任务] +C --> D{是否月末?} +D --> |否| E[计算当月平均值] +D --> |是| F[生成月度报告] +E --> G[与预期值比较] +G --> H[发送预警] +F --> I[存档历史数据] +``` + +系统每天收集销售额数据,当月内持续计算平均值作为预期值。到月末时,系统生成完整的月度报告,与历史月平均值进行对比分析,帮助管理层了解销售趋势。 + +**本节来源** +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java) +- [ActualValues.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\ActualValues.java) + +## 特殊日期影响分析 + +### 闰月处理 + +在农历闰月的情况下,系统仍然按照公历月份进行计算。由于月平均值策略基于公历日期,闰月不会对计算结果产生特殊影响。系统会将闰月视为一个完整的月份,包含其所有天数。 + +### 月末天数变化 + +不同月份的天数变化(28、29、30、31天)已被策略正确处理: +- 2月(28或29天):系统自动识别闰年,正确计算2月的平均值 +- 30天月份:正常计算30天的平均值 +- 31天月份:正常计算31天的平均值 + +这种处理方式确保了不同长度月份的平均值具有可比性,不会因为月份长度差异而产生偏差。 + +### 跨月计算边界 + +系统在处理跨月计算时,严格遵循左闭右开区间原则: +- 起始时间包含:`>= date_format(${data_time}, 'yyyy-MM-01')` +- 结束时间不包含:`< date_add(date_format(${data_time}, 'yyyy-MM-dd'),1)` + +这种边界处理方式避免了数据重复计算,确保了统计结果的准确性。 + +**本节来源** +- [SparkMonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\SparkMonthlyAvg.java#L47-L48) +- [FlinkMetricScript.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkMetricScript.java#L64-L65) + +## 结论 + +月平均值策略通过MonthlyAvg和SparkMonthlyAvg类的协同工作,实现了高效、准确的月度平均值计算。该策略具有以下特点: + +1. **引擎无关性**:通过抽象层设计,支持Spark、Flink等多种计算引擎 +2. **时间准确性**:精确处理月度时间窗口和边界条件 +3. **性能优化**:针对大规模数据进行了查询优化 +4. **灵活性**:支持多种配置参数,适应不同应用场景 + +在财务指标监控等实际应用中,该策略能够提供可靠的预期值参考,帮助用户及时发现数据异常,确保业务决策的准确性。未来可进一步优化方向包括支持更多时间粒度(如季度、年度平均值)和引入加权平均等更复杂的计算方法。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\347\211\271\346\256\212\347\255\226\347\225\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\347\211\271\346\256\212\347\255\226\347\225\245.md" new file mode 100644 index 00000000..eac658a8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\347\211\271\346\256\212\347\255\226\347\225\245.md" @@ -0,0 +1,213 @@ +# 特殊策略 + + +**本文档引用的文件** +- [TableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-table-rows/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java) +- [TargetTableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-target-table-rows/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java) +- [ExpectedValue.java](file://datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [TableRowCount.java](file://datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java) +- [LocalSingleTableMetricBuilder.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考量](#性能考量) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 引言 +本文档详细阐述了数据质量监控系统中两种特殊预期值策略的实现原理:**表总行数**(TableTotalRows)和**目标表总行数**(TargetTableTotalRows)。这两种策略专门用于数据量一致性校验,通过获取源表或目标表的总行数作为预期值,与实际值进行对比,从而验证数据迁移、ETL流程等场景下的数据完整性。文档将深入分析其技术实现、配置方法、适用场景及在大规模数据集下的优化方案。 + +## 核心组件 +本系统的核心在于其可扩展的插件化架构,其中 `TableTotalRows` 和 `TargetTableTotalRows` 是 `ExpectedValue` 接口的具体实现。它们负责生成用于查询预期行数的SQL语句。`TableRowCount` 作为具体的度量指标(Metric),定义了如何计算实际行数。整个流程由配置构建器(如 `LocalSingleTableMetricBuilder`)协调,将预期值和实际值的计算结果整合到最终的执行计划中。 + +**核心组件** +- [TableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-table-rows/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java#L26-L75) +- [TargetTableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-target-table-rows/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java#L26-L75) +- [TableRowCount.java](file://datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java#L32-L127) + +## 架构概述 +系统采用分层架构,上层是用户配置的度量任务,底层是通过SPI(Service Provider Interface)机制加载的各类插件。当用户选择“表行数检查”这一度量类型时,系统会根据配置的预期值策略(如“表总行数”)动态加载对应的 `ExpectedValue` 插件,并与 `TableRowCount` 度量插件协同工作,最终生成一个包含实际值和预期值查询的完整执行流程。 + +```mermaid +graph TB +subgraph "用户配置" +A["用户选择度量: 表行数检查"] +B["用户选择预期值策略: 表总行数 / 目标表总行数"] +end +subgraph "插件系统" +C[TableRowCount] --> D[ExpectedValue] +D --> E[TableTotalRows] +D --> F[TargetTableTotalRows] +end +subgraph "执行引擎" +G[LocalSingleTableMetricBuilder] +H[ExpectedValueExecutor] +end +A --> G +B --> G +G --> C +G --> D +C --> H +D --> H +``` + +**图表来源** +- [TableRowCount.java](file://datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java) +- [TableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-table-rows/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java) +- [TargetTableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-target-table-rows/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java) +- [LocalSingleTableMetricBuilder.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java) + +## 详细组件分析 + +### TableTotalRows 和 TargetTableTotalRows 策略分析 +`TableTotalRows` 和 `TargetTableTotalRows` 是实现数据量一致性校验的核心策略。它们都实现了 `ExpectedValue` 接口,但查询的数据源不同。 + +#### 实现原理与独特作用 +这两个策略的核心作用是为数据质量校验提供一个动态的、基于数据库查询的预期值,而非一个静态的固定值。这在数据迁移、增量同步等场景中至关重要,因为预期的数据量是动态变化的。 + +- **TableTotalRows (表总行数)**: 此策略通过执行 `SELECT COUNT(1) FROM ${table}` 来获取**源表**的当前总行数作为预期值。它适用于验证单个表的数据完整性,例如,确保ETL流程处理了源表中的所有记录。 +- **TargetTableTotalRows (目标表总行数)**: 此策略通过执行 `SELECT COUNT(1) FROM ${table2}` 来获取**目标表**的当前总行数作为预期值。它主要用于数据迁移或同步场景,用于验证目标端的数据量是否与源端一致,从而判断同步是否成功。 + +这种设计的**独特作用**在于,它将预期值的确定从“预设的静态值”转变为“实时查询的动态值”,极大地提高了校验的灵活性和准确性。 + +#### 预期值获取与验证逻辑 +1. **预期值获取**: 策略通过 `getExecuteSql` 方法生成一个SQL查询语句。该语句的核心是 `COUNT(1)` 聚合函数,用于计算指定表的行数。`${table}` 或 `${table2}` 是占位符,会在运行时被实际的表名替换。 +2. **实际值获取**: 与此同时,`TableRowCount` 度量插件会生成一个类似的SQL语句(`SELECT COUNT(1) FROM ${table}`)来计算实际参与校验的数据行数。 +3. **验证逻辑**: 执行引擎会分别执行这两个SQL,得到两个结果:`actual_value` 和 `expected_value`。系统会根据配置的比较算子(如等于、大于等于等)和阈值,判断 `actual_value` 是否与 `expected_value` 一致。如果一致,则校验通过;否则,校验失败。 + +```mermaid +sequenceDiagram +participant 用户 as 用户 +participant 配置构建器 as LocalSingleTableMetricBuilder +participant 度量插件 as TableRowCount +participant 预期值插件 as ExpectedValue +participant 执行引擎 as ExpectedValueExecutor +participant 数据库 as 数据库 +用户->>配置构建器 : 配置“表行数检查”任务 +配置构建器->>度量插件 : 获取实际值SQL +度量插件-->>配置构建器 : 返回实际值SQL +配置构建器->>预期值插件 : 获取预期值SQL +预期值插件-->>配置构建器 : 返回预期值SQL +配置构建器->>执行引擎 : 提交执行计划 +执行引擎->>数据库 : 执行实际值查询 +执行引擎->>数据库 : 执行预期值查询 +数据库-->>执行引擎 : 返回实际值 +数据库-->>执行引擎 : 返回预期值 +执行引擎->>执行引擎 : 比较 actual_value 和 expected_value +执行引擎-->>用户 : 返回校验结果 +``` + +**图表来源** +- [TableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-table-rows/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java#L28-L52) +- [TargetTableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-target-table-rows/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java#L28-L52) +- [TableRowCount.java](file://datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java#L80-L92) +- [ExpectedValueExecutor.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-transform/src/main/java/io/datavines/engine/local/transform/sql/ExpectedValueExecutor.java#L33-L47) + +### 配置方法、性能考量与适用场景 +#### 配置方法 +配置主要通过JSON或UI界面完成,关键参数包括: +- `metric_type`: 设置为 `table_row_count`,指定使用行数检查度量。 +- `expected_type`: 设置为 `table_total_rows` 或 `target_table_total_rows`,以选择预期值策略。 +- `table`: 指定源表名称。 +- `target_table`: (仅当使用 `target_table_total_rows` 时)指定目标表名称。 +- `filter`: 可选,为查询添加WHERE条件,例如 `status = 'active'`。 + +这些参数通过 `ConfigConstants` 中定义的常量(如 `TABLE`, `TARGET_TABLE`, `FILTER`)在代码中进行引用和处理。 + +**核心组件** +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java#L24-L36) +- [LocalSingleTableMetricBuilder.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java#L48-L55) + +#### 性能考量 +- **全表扫描**: `COUNT(1)` 操作在没有合适索引的情况下会导致全表扫描,对于超大规模表,查询可能非常耗时。 +- **执行频率**: 如果校验任务频繁执行,对数据库的性能会产生持续压力。 +- **优化建议**: 确保被计数的表有高效的索引(如主键索引),或者在非高峰时段执行此类校验任务。 + +#### 适用场景 +- **数据迁移验证**: 在将数据从旧系统迁移到新系统后,使用 `TargetTableTotalRows` 策略,确保新旧两个表的行数一致。 +- **ETL流程完整性检查**: 在ETL流程结束后,使用 `TableTotalRows` 策略,验证抽取、转换、加载的总记录数是否与源数据一致。 +- **数据同步监控**: 监控两个数据库之间的同步状态,确保没有数据丢失。 + +#### 大规模数据集优化方案 +对于超大规模数据集,直接使用 `COUNT(1)` 可能不切实际。优化方案包括: +1. **元数据查询**: 某些数据库(如Hive)的元数据存储(如Metastore)中会缓存表的行数统计信息。可以开发一个 `ExpectedValue` 插件,直接从元数据中读取行数,避免全表扫描。 +2. **采样估算**: 对于不要求绝对精确的场景,可以通过对表进行采样(如 `TABLESAMPLE`)来估算总行数。 +3. **增量计算**: 维护一个单独的计数器表,每次数据变更时更新计数,校验时直接查询该计数器。 + +## 依赖分析 +系统通过SPI机制实现高度解耦。`ExpectedValue` 接口是核心契约,`TableTotalRows` 和 `TargetTableTotalRows` 依赖于 `ConfigConstants` 来获取配置项的键名。`LocalSingleTableMetricBuilder` 作为协调者,依赖于 `PluginLoader` 来动态加载 `ExpectedValue` 和 `SqlMetric` 插件,从而将它们组合成一个完整的任务。 + +```mermaid +classDiagram +class ExpectedValue { +<> ++getName() String ++getZhName() String ++getKey(Map) String ++getExecuteSql(Map) String ++getOutputTable(Map) String ++isNeedDefaultDatasource() boolean ++prepare(Map) void +} +class TableTotalRows { +-sql StringBuilder ++getName() String ++getZhName() String ++getExecuteSql(Map) String ++prepare(Map) void +} +class TargetTableTotalRows { +-sql StringBuilder ++getName() String ++getZhName() String ++getExecuteSql(Map) String ++prepare(Map) void +} +class ConfigConstants { ++TABLE String ++TARGET_TABLE String ++FILTER String ++METRIC_UNIQUE_KEY String +} +class LocalSingleTableMetricBuilder { +-buildSinkConfigs() void +} +class PluginLoader { ++getPluginLoader(Class) PluginLoader ++getNewPlugin(String) T +} +ExpectedValue <|-- TableTotalRows +ExpectedValue <|-- TargetTableTotalRows +LocalSingleTableMetricBuilder ..> PluginLoader : "使用" +LocalSingleTableMetricBuilder ..> ExpectedValue : "加载" +TableTotalRows ..> ConfigConstants : "引用常量" +TargetTableTotalRows ..> ConfigConstants : "引用常量" +``` + +**图表来源** +- [ExpectedValue.java](file://datavines-metric-api/src/main/java/io/datavines/metric/api/ExpectedValue.java) +- [TableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-table-rows/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java) +- [TargetTableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-target-table-rows/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java) +- [LocalSingleTableMetricBuilder.java](file://datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java) + +## 性能考量 +如前所述,`TableTotalRows` 和 `TargetTableTotalRows` 策略的主要性能瓶颈在于 `COUNT(1)` 操作。在大规模数据集上,这可能导致校验任务执行时间过长,影响整体数据处理流程的效率。因此,在生产环境中使用这些策略时,必须评估其对数据库性能的影响,并考虑采用元数据查询等优化方案。 + +## 故障排除指南 +- **校验失败**: 首先检查 `actual_value` 和 `expected_value` 的具体数值。如果两者不一致,检查源表和目标表的数据是否确实存在差异,或检查 `filter` 条件是否正确。 +- **执行超时**: 如果校验任务超时,很可能是由于表过大导致 `COUNT(1)` 查询耗时过长。应考虑优化查询或调整任务超时时间。 +- **SQL语法错误**: 检查配置的表名、列名是否正确,以及 `filter` 条件的SQL语法是否符合目标数据库的要求。 + +**故障排除指南** +- [TableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-table-rows/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java#L66-L74) +- [TargetTableTotalRows.java](file://datavines-metric-expected-plugins/datavines-metric-expected-target-table-rows/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java#L66-L74) + +## 结论 +`TableTotalRows` 和 `TargetTableTotalRows` 策略为数据质量监控提供了强大的数据量一致性校验能力。通过将预期值动态化,它们能够有效应用于数据迁移、ETL和数据同步等关键场景。尽管在大规模数据集上存在性能挑战,但其清晰的插件化设计为实现更高效的优化方案(如元数据查询)提供了良好的基础。合理配置和使用这些策略,可以显著提升数据管道的可靠性和可信度。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237.md" new file mode 100644 index 00000000..d14c3b4f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-metric\346\250\241\345\235\227/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237/\351\242\204\346\234\237\345\200\274\350\256\241\347\256\227\347\263\273\347\273\237.md" @@ -0,0 +1,345 @@ +# 预期值计算系统 + + +**本文档引用的文件** +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java) +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java) +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java) +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java) +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java) +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java) +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java) +- [TableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-table-rows\src\main\java\io\datavines\metric\expected\plugin\TableTotalRows.java) +- [TargetTableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-target-table-rows\src\main\java\io\datavines\metric\expected\plugin\TargetTableTotalRows.java) +- [None.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-none\src\main\java\io\datavines\metric\expected\plugin\None.java) +- [AbstractExpectedValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-base\src\main\java\io\datavines\metric\expected\plugin\AbstractExpectedValue.java) +- [SPI.java](file://datavines-spi\src\main\java\io\datavines\spi\SPI.java) +- [PluginLoader.java](file://datavines-spi\src\main\java\io\datavines\spi\PluginLoader.java) +- [BaseJobConfigurationBuilder.java](file://datavines-engine\datavines-engine-config\src\main\java\io\datavines\engine\config\BaseJobConfigurationBuilder.java) + + +## 目录 +1. [引言](#引言) +2. [预期值在数据质量验证中的核心作用](#预期值在数据质量验证中的核心作用) +3. [预期值计算策略](#预期值计算策略) +4. [预期值插件的SPI机制和注册方式](#预期值插件的spi机制和注册方式) +5. [特殊策略的实现原理](#特殊策略的实现原理) +6. [配置最佳实践和性能调优建议](#配置最佳实践和性能调优建议) +7. [复杂案例分析](#复杂案例分析) +8. [结论](#结论) + +## 引言 + +预期值计算系统是数据质量验证框架中的核心组件,负责为数据质量指标提供基准参考值。该系统通过多种计算策略,为数据质量检查提供可靠的预期基准,从而判断数据质量是否达标。本系统采用插件化架构,支持多种计算策略,并通过SPI机制实现灵活的扩展和注册。 + +**本节不分析具体源文件,因此不提供来源** + +## 预期值在数据质量验证中的核心作用 + +预期值在数据质量验证中扮演着基准参照物的角色。通过将实际值与预期值进行比较,系统能够判断数据质量是否符合预期标准。预期值的准确性直接影响数据质量评估的可靠性。系统支持多种预期值计算策略,以适应不同的业务场景和数据特征。 + +**本节不分析具体源文件,因此不提供来源** + +## 预期值计算策略 + +### 固定值策略 (FixValue) + +固定值策略是最简单的预期值计算方式,适用于预期值已知且不变的场景。该策略不进行任何计算,直接使用预设的固定值作为预期值。 + +```mermaid +classDiagram +class FixValue { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +``` + +**图示来源** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java#L25-L62) + +**本节来源** +- [FixValue.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-fix\src\main\java\io\datavines\metric\expected\plugin\FixValue.java#L25-L62) + +### 日均值策略 (DailyAvg) + +日均值策略计算指定时间段内实际值的平均值作为预期值。该策略适用于数据波动较小、需要基于历史数据进行趋势分析的场景。 + +```mermaid +classDiagram +class DailyAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +``` + +**图示来源** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L25-L39) + +**本节来源** +- [DailyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-daily-avg\src\main\java\io\datavines\metric\expected\plugin\DailyAvg.java#L25-L39) + +### 最近7天均值策略 (Last7DayAvg) + +最近7天均值策略计算最近7天内实际值的平均值作为预期值。该策略适用于需要考虑短期趋势的场景。 + +```mermaid +classDiagram +class Last7DayAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +``` + +**图示来源** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java#L24-L38) + +**本节来源** +- [Last7DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last7day-avg\src\main\java\io\datavines\metric\expected\plugin\Last7DayAvg.java#L24-L38) + +### 最近30天均值策略 (Last30DayAvg) + +最近30天均值策略计算最近30天内实际值的平均值作为预期值。该策略适用于需要考虑中长期趋势的场景。 + +```mermaid +classDiagram +class Last30DayAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +``` + +**图示来源** +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java#L24-L38) + +**本节来源** +- [Last30DayAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-last30day-avg\src\main\java\io\datavines\metric\expected\plugin\Last30DayAvg.java#L24-L38) + +### 月均值策略 (MonthlyAvg) + +月均值策略计算当月内实际值的平均值作为预期值。该策略适用于需要按月度周期进行数据质量评估的场景。 + +```mermaid +classDiagram +class MonthlyAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +``` + +**图示来源** +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java#L24-L38) + +**本节来源** +- [MonthlyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-monthly-avg\src\main\java\io\datavines\metric\expected\plugin\MonthlyAvg.java#L24-L38) + +### 周均值策略 (WeeklyAvg) + +周均值策略计算当周内实际值的平均值作为预期值。该策略适用于需要按周度周期进行数据质量评估的场景。 + +```mermaid +classDiagram +class WeeklyAvg { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +``` + +**图示来源** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java#L25-L38) + +**本节来源** +- [WeeklyAvg.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-weekly-avg\src\main\java\io\datavines\metric\expected\plugin\WeeklyAvg.java#L25-L38) + +## 预期值插件的SPI机制和注册方式 + +### SPI机制 + +预期值插件系统采用SPI(Service Provider Interface)机制实现插件化架构。通过`@SPI`注解标记接口,系统在运行时动态加载实现类。 + +```mermaid +classDiagram +class SPI { ++value() String +} +class ExpectedValue { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +SPI <|-- ExpectedValue +``` + +**图示来源** +- [SPI.java](file://datavines-spi\src\main\java\io\datavines\spi\SPI.java#L1-L32) +- [ExpectedValue.java](file://datavines-metric\datavines-metric-api\src\main\java\io\datavines\metric\api\ExpectedValue.java#L23-L65) + +### 插件注册方式 + +系统通过`PluginLoader`类实现插件的加载和注册。插件实现类通过配置文件声明,系统在启动时自动加载。 + +```mermaid +sequenceDiagram +participant PluginLoader +participant ExpectedValue +participant FixValue +participant DailyAvg +PluginLoader->>PluginLoader : getPluginLoader(ExpectedValue.class) +PluginLoader->>PluginLoader : loadPluginClasses() +PluginLoader->>PluginLoader : getOrCreatePlugin("fix_value") +PluginLoader-->>FixValue : 返回FixValue实例 +PluginLoader->>PluginLoader : getOrCreatePlugin("daily_avg") +PluginLoader-->>DailyAvg : 返回DailyAvg实例 +``` + +**图示来源** +- [PluginLoader.java](file://datavines-spi\src\main\java\io\datavines\spi\PluginLoader.java#L84-L200) + +**本节来源** +- [PluginLoader.java](file://datavines-spi\src\main\java\io\datavines\spi\PluginLoader.java#L84-L200) + +## 特殊策略的实现原理 + +### 表总行数策略 (TableTotalRows) + +表总行数策略通过执行SQL查询计算指定表的总行数作为预期值。该策略支持通过filter参数添加过滤条件。 + +```mermaid +classDiagram +class TableTotalRows { +-sql StringBuilder ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +``` + +**图示来源** +- [TableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-table-rows\src\main\java\io\datavines\metric\expected\plugin\TableTotalRows.java#L26-L75) + +**本节来源** +- [TableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-table-rows\src\main\java\io\datavines\metric\expected\plugin\TableTotalRows.java#L26-L75) + +### 目标表总行数策略 (TargetTableTotalRows) + +目标表总行数策略与表总行数策略类似,但查询的是目标表(table2)的总行数。该策略用于比较源表和目标表的数据量一致性。 + +```mermaid +classDiagram +class TargetTableTotalRows { +-sql StringBuilder ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +``` + +**图示来源** +- [TargetTableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-target-table-rows\src\main\java\io\datavines\metric\expected\plugin\TargetTableTotalRows.java#L26-L75) + +**本节来源** +- [TargetTableTotalRows.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-target-table-rows\src\main\java\io\datavines\metric\expected\plugin\TargetTableTotalRows.java#L26-L75) + +### 无预期值策略 (None) + +无预期值策略表示不使用预期值进行比较。该策略适用于只需要获取实际值的场景。 + +```mermaid +classDiagram +class None { ++getName() String ++getZhName() String ++getKey(inputParameter) String ++getExecuteSql(inputParameter) String ++getOutputTable(inputParameter) String ++isNeedDefaultDatasource() boolean ++prepare(config) void +} +``` + +**图示来源** +- [None.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-none\src\main\java\io\datavines\metric\expected\plugin\None.java#L25-L63) + +**本节来源** +- [None.java](file://datavines-metric\datavines-metric-expected-plugins\datavines-metric-expected-none\src\main\java\io\datavines\metric\expected\plugin\None.java#L25-L63) + +## 配置最佳实践和性能调优建议 + +### 配置最佳实践 + +1. 根据业务场景选择合适的预期值计算策略 +2. 对于历史数据稳定的指标,使用固定值策略 +3. 对于有周期性波动的指标,使用相应周期的均值策略 +4. 合理设置filter参数,避免全表扫描 +5. 定期评估预期值的合理性,及时调整计算策略 + +### 性能调优建议 + +1. 为查询字段建立适当的索引 +2. 避免在大表上执行全表计数操作 +3. 合理设置查询时间范围,避免查询过大数据量 +4. 使用缓存机制减少重复计算 +5. 监控查询性能,及时优化慢查询 + +**本节不分析具体源文件,因此不提供来源** + +## 复杂案例分析 + +### 多维度预期值组合使用 + +在实际业务中,往往需要结合多种预期值策略进行综合评估。例如,对于一个电商订单表,可以同时使用以下策略: + +1. 使用表总行数策略监控每日订单量 +2. 使用日均值策略监控订单金额的波动 +3. 使用固定值策略监控特定促销活动的预期订单量 + +这种多维度的监控方式能够更全面地反映数据质量状况,及时发现异常。 + +**本节不分析具体源文件,因此不提供来源** + +## 结论 + +预期值计算系统通过灵活的插件化架构和多种计算策略,为数据质量验证提供了可靠的基准参考。系统采用SPI机制实现插件的动态加载和注册,具有良好的扩展性。通过合理选择和配置预期值策略,可以有效提升数据质量监控的准确性和效率。 + +**本节不分析具体源文件,因此不提供来源** \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/datavines-notification\346\250\241\345\235\227.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/datavines-notification\346\250\241\345\235\227.md" new file mode 100644 index 00000000..0d7bc780 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/datavines-notification\346\250\241\345\235\227.md" @@ -0,0 +1,273 @@ +# datavines-notification模块 + + +**本文档引用文件** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) +- [SlaSenderMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaSenderMessage.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [NotificationConstants.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/constants/NotificationConstants.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +datavines-notification模块是DataVines平台中的告警通知系统,负责在数据质量检查失败或SLA(服务等级协议)违规时向相关人员发送通知。该模块支持多种通知渠道,包括钉钉、企业微信、邮件和飞书等,通过灵活的SPI机制实现通知渠道的扩展。模块提供了完整的SLA配置、触发条件和通知策略管理功能,确保数据质量问题能够及时被发现和处理。 + +## 项目结构 +datavines-notification模块采用分层架构设计,包含API、核心实现和插件三个主要部分。API层定义了通知系统的核心接口和数据模型,核心层实现了通知管理器和调度逻辑,插件层则提供了各种通知渠道的具体实现。 + +```mermaid +graph TD +subgraph "datavines-notification" +subgraph "API层" +NotificationAPI[通知API] +Entity[实体类] +SPI[SPI接口] +end +subgraph "核心层" +NotificationManager[通知管理器] +Client[通知客户端] +end +subgraph "插件层" +DingTalk[钉钉插件] +Email[邮件插件] +Lark[飞书插件] +WecomBot[企业微信插件] +end +NotificationAPI --> NotificationManager +NotificationManager --> DingTalk +NotificationManager --> Email +NotificationManager --> Lark +NotificationManager --> WecomBot +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +**章节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +## 核心组件 +datavines-notification模块的核心组件包括通知管理器(NotificationManager)、通知消息模型和SPI插件接口。通知管理器负责协调各种通知渠道的调用,消息模型定义了通知内容的结构,SPI接口则为扩展新的通知渠道提供了标准。 + +**章节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) + +## 架构概述 +datavines-notification模块采用插件化架构,通过SPI机制实现通知渠道的动态加载和管理。通知管理器作为核心组件,负责接收通知请求,根据配置调用相应的通知插件,并汇总通知结果。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant NotificationManager as "通知管理器" +participant PluginLoader as "插件加载器" +participant Plugin as "通知插件" +Client->>NotificationManager : 发送通知请求 +NotificationManager->>PluginLoader : 获取支持的插件 +PluginLoader-->>NotificationManager : 返回插件列表 +NotificationManager->>Plugin : 调用notify方法 +Plugin->>Plugin : 执行具体通知逻辑 +Plugin-->>NotificationManager : 返回通知结果 +NotificationManager-->>Client : 返回汇总结果 +Note over Client,Plugin : 通知管理器协调各插件完成通知任务 +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +## 详细组件分析 + +### 通知管理器分析 +通知管理器是datavines-notification模块的核心组件,负责协调和管理所有通知操作。它通过SPI机制动态加载支持的通知插件,并根据配置调用相应的插件来发送通知。 + +#### 通知管理器类图 +```mermaid +classDiagram +class NotificationManager { ++Set supportedPlugins ++NotificationManager() ++SlaNotificationResult notify(SlaNotificationMessage, Map>) +} +class SlaNotificationMessage { ++Long slaId ++String subject ++String message +} +class SlaNotificationResult { ++Boolean status ++List records ++SlaNotificationResult merge(SlaNotificationResult) +} +class SlaConfigMessage { ++Long id ++String type ++String config +} +class SlaSenderMessage { ++Long id ++Long workspaceId ++String type ++String name ++String config +} +NotificationManager --> SlaNotificationMessage : "接收" +NotificationManager --> SlaNotificationResult : "返回" +NotificationManager --> SlaConfigMessage : "使用" +NotificationManager --> SlaSenderMessage : "使用" +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) +- [SlaSenderMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaSenderMessage.java) + +**章节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +### SLA通知机制分析 +SLA通知机制是datavines-notification模块的核心功能,负责在SLA违规时发送通知。该机制通过配置化的消息模板和灵活的通知策略,确保通知内容的准确性和及时性。 + +#### SLA通知流程图 +```mermaid +flowchart TD +Start([开始]) --> ValidateConfig["验证通知配置"] +ValidateConfig --> ConfigValid{"配置有效?"} +ConfigValid --> |否| ReturnError["返回错误"] +ConfigValid --> |是| FindPlugins["查找支持的插件"] +FindPlugins --> PluginFound{"找到插件?"} +PluginFound --> |否| ReturnError +PluginFound --> |是| CallPlugin["调用通知插件"] +CallPlugin --> PluginExecute["执行通知逻辑"] +PluginExecute --> CheckResult{"通知成功?"} +CheckResult --> |否| RecordFailure["记录失败"] +CheckResult --> |是| RecordSuccess["记录成功"] +RecordFailure --> ContinueLoop +RecordSuccess --> ContinueLoop +ContinueLoop --> MorePlugins{"还有更多插件?"} +MorePlugins --> |是| CallPlugin +MorePlugins --> |否| MergeResults["合并通知结果"] +MergeResults --> ReturnResult["返回结果"] +ReturnError --> End([结束]) +ReturnResult --> End +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +**章节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +### 通知插件SPI机制分析 +通知插件SPI机制是datavines-notification模块的扩展基础,通过标准接口定义,允许开发者轻松添加新的通知渠道。 + +#### SPI机制类图 +```mermaid +classDiagram +class SlasHandlerPlugin { +<> ++SlaNotificationResult notify(SlaNotificationMessage, Map>) ++String getConfigSenderJson() ++String getConfigJson() +} +class DingTalkSlasHandlerPlugin { ++SlaNotificationResult notify(SlaNotificationMessage, Map>) ++String getConfigSenderJson() ++String getConfigJson() +} +class EmailSlasHandlerPlugin { ++SlaNotificationResult notify(SlaNotificationMessage, Map>) ++String getConfigSenderJson() ++String getConfigJson() +} +class LarkSlasHandlerPlugin { ++SlaNotificationResult notify(SlaNotificationMessage, Map>) ++String getConfigSenderJson() ++String getConfigJson() +} +class WecomBotSlasHandlerPlugin { ++SlaNotificationResult notify(SlaNotificationMessage, Map>) ++String getConfigSenderJson() ++String getConfigJson() +} +SlasHandlerPlugin <|-- DingTalkSlasHandlerPlugin +SlasHandlerPlugin <|-- EmailSlasHandlerPlugin +SlasHandlerPlugin <|-- LarkSlasHandlerPlugin +SlasHandlerPlugin <|-- WecomBotSlasHandlerPlugin +``` + +**图示来源** +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java) + +**章节来源** +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +## 依赖分析 +datavines-notification模块依赖于datavines-spi模块的插件加载机制,以及datavines-common模块的通用工具类。通过SPI机制,模块能够动态加载和管理各种通知插件,实现了高度的可扩展性。 + +```mermaid +graph TD +subgraph "datavines-notification" +NotificationManager[通知管理器] +SPIInterface[SPI接口] +end +subgraph "依赖模块" +SPI[datavines-spi] +Common[datavines-common] +end +NotificationManager --> SPI +SPIInterface --> SPI +NotificationManager --> Common +SPIInterface --> Common +Note over SPI,Common: 通知模块依赖SPI和通用工具模块 +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +**章节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +## 性能考虑 +datavines-notification模块在设计时考虑了性能和可靠性。通知管理器采用批量处理机制,能够同时处理多个通知请求。通过异步调用和结果合并,确保了通知操作的高效性。同时,模块实现了错误重试机制,提高了通知的可靠性。 + +## 故障排除指南 +当遇到通知发送失败的问题时,可以按照以下步骤进行排查: +1. 检查通知配置是否正确,包括接收人、通知渠道等 +2. 验证通知插件的配置参数是否完整 +3. 查看系统日志,定位具体的错误信息 +4. 确认网络连接是否正常,特别是外部通知服务的可达性 +5. 检查SPI插件是否正确加载 + +**章节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +## 结论 +datavines-notification模块通过灵活的SPI机制和模块化设计,提供了一个可扩展、可靠的通知系统。该模块不仅支持多种通知渠道,还提供了完善的SLA管理和通知策略配置功能。通过合理的架构设计和性能优化,确保了通知系统的高效性和可靠性,为数据质量管理提供了有力的支持。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\344\274\201\344\270\232\345\276\256\344\277\241\351\200\232\347\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\344\274\201\344\270\232\345\276\256\344\277\241\351\200\232\347\237\245.md" new file mode 100644 index 00000000..c20a5c6d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\344\274\201\344\270\232\345\276\256\344\277\241\351\200\232\347\237\245.md" @@ -0,0 +1,304 @@ +# 企业微信通知 + + +**本文档引用的文件** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSlasHandlerPlugin.java) +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java) +- [WecomBotConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotConstants.java) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\ReceiverConfig.java) +- [NotificationConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\NotificationConfig.java) +- [ContentUtil.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\utils\ContentUtil.java) +- [SlaNotificationMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationMessage.java) +- [SlaSenderMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaSenderMessage.java) +- [SlaConfigMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaConfigMessage.java) +- [WecomBotRes.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\WecomBotRes.java) + + +## 目录 +1. [简介](#简介) +2. [WecomBotSlasHandlerPlugin处理SLA告警](#wecombotslashandlerplugin处理sla告警) +3. [WecomBotSender实现分析](#wecombotsender实现分析) +4. [NotificationConfig配置实体](#notificationconfig配置实体) +5. [消息模板示例](#消息模板示例) +6. [API返回结果处理与错误实践](#api返回结果处理与错误实践) + +## 简介 +本文档详细介绍了Datavines平台中企业微信通知插件的实现机制。该插件通过WecomBotSlasHandlerPlugin处理SLA(服务等级协议)告警,并利用WecomBotSender调用企业微信机器人API发送通知。文档将深入分析核心组件的实现细节,包括消息构建、配置管理以及错误处理策略。 + +## WecomBotSlasHandlerPlugin处理SLA告警 + +WecomBotSlasHandlerPlugin是SLA告警处理的核心组件,实现了SlasHandlerPlugin接口,负责处理SLA告警并调用企业微信机器人API。 + +该插件的主要功能流程如下: +1. 过滤出类型为"wecombot"的发送器配置 +2. 解析接收器配置信息 +3. 调用WecomBotSender发送消息 +4. 收集并返回发送结果 + +插件通过`notify`方法接收SLA告警消息和配置信息,其中: +- `SlaNotificationMessage`包含告警的主题和内容 +- `Map>`包含发送器配置和接收器配置 + +当检测到发送失败时,插件会将整体状态设置为失败,并记录失败详情。 + +```mermaid +sequenceDiagram +participant SLA系统 as SLA系统 +participant WecomBotSlasHandlerPlugin as WecomBotSlasHandlerPlugin +participant WecomBotSender as WecomBotSender +participant 企业微信API as 企业微信API +SLA系统->>WecomBotSlasHandlerPlugin : 发送SLA告警 +WecomBotSlasHandlerPlugin->>WecomBotSlasHandlerPlugin : 过滤wecombot类型发送器 +WecomBotSlasHandlerPlugin->>WecomBotSlasHandlerPlugin : 解析接收器配置 +WecomBotSlasHandlerPlugin->>WecomBotSender : 调用sendMsg发送消息 +WecomBotSender->>企业微信API : POST请求发送消息 +企业微信API-->>WecomBotSender : 返回响应结果 +WecomBotSender-->>WecomBotSlasHandlerPlugin : 返回发送结果 +WecomBotSlasHandlerPlugin-->>SLA系统 : 返回最终处理结果 +``` + +**图示来源** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSlasHandlerPlugin.java#L34-L62) +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L40-L73) + +**本节来源** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSlasHandlerPlugin.java#L34-L62) + +## WecomBotSender实现分析 + +WecomBotSender是企业微信消息发送的核心实现类,负责构建和发送不同类型的消息到企业微信机器人。 + +### 消息发送流程 +WecomBotSender的`sendMsg`方法实现了完整的消息发送流程: + +1. **输入验证**:检查接收器集合是否为空 +2. **配置清理**:移除webhook地址为空的接收器 +3. **消息构建**:调用`getMarkdownMessage`方法构建Markdown格式消息 +4. **参数准备**:使用ContentUtil创建API调用参数 +5. **API调用**:通过HttpUtils发送POST请求 +6. **结果处理**:解析API响应并记录发送结果 + +### 消息类型支持 +目前实现主要支持Markdown消息类型,通过WecomBotConstants常量定义了消息类型和格式: + +- `MSG_TYPE`: "msgtype" - 消息类型字段 +- `MARKDOWN`: "markdown" - Markdown消息类型 +- `CONTENT`: "content" - 内容字段 +- `FIRST_TITLE_START`: "# " - 一级标题前缀 +- `QUOTE_START`: "> " - 引用文本前缀 +- `END`: "\n" - 换行符 + +### 消息构建机制 +`getMarkdownMessage`方法负责将原始消息内容转换为符合企业微信Markdown格式的消息: + +1. 添加一级标题(使用subject作为标题) +2. 处理内容中的JSON数组 +3. 对特定格式的消息(如"任务执行记录")创建超链接 +4. 使用引用格式包装每条消息 +5. 添加适当的换行符 + +```mermaid +classDiagram +class WecomBotSender { ++sendMsg(receiverSet, subject, message) SlaNotificationResultRecord +-getMarkdownMessage(subject, content) String +} +class ContentUtil { ++createParamMap(elements) Map~String,Object~ +} +class WecomBotConstants { ++MSG_TYPE : String ++MARKDOWN : String ++CONTENT : String ++FIRST_TITLE_START : String ++QUOTE_START : String ++END : String +} +class WecomBotRes { +-errcode : String +-errmsg : String ++success() boolean ++parseFromJson(json) WecomBotRes +} +WecomBotSender --> ContentUtil : "使用" +WecomBotSender --> WecomBotConstants : "引用" +WecomBotSender --> WecomBotRes : "解析响应" +WecomBotSender --> HttpUtils : "发送HTTP请求" +WecomBotSender --> JSONUtils : "JSON处理" +``` + +**图示来源** +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L38-L73) +- [ContentUtil.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\utils\ContentUtil.java#L22-L38) +- [WecomBotConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotConstants.java#L19-L26) +- [WecomBotRes.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\WecomBotRes.java#L24-L43) + +**本节来源** +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L38-L95) +- [ContentUtil.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\utils\ContentUtil.java#L22-L38) + +## NotificationConfig配置实体 + +NotificationConfig是企业微信通知的配置实体类,定义了通知相关的配置参数。 + +### 核心配置参数 +当前实现中,NotificationConfig主要包含以下配置参数: + +- `receiverType`: 接收器类型,用于区分不同类型的接收器配置 + +在实际使用中,接收器的具体配置(如webhook地址)存储在ReceiverConfig类中,通过JSON字符串形式传递。 + +### 配置管理机制 +WecomBotSlasHandlerPlugin通过`getConfigJson`方法提供配置项定义,目前主要包含: + +- `webhook`: 企业微信机器人的Webhook地址,标记为必填项 + +配置系统使用PluginParams、InputParam和Validate等类来定义和验证配置参数,确保配置的完整性和正确性。 + +```mermaid +classDiagram +class NotificationConfig { +-receiverType : String +} +class ReceiverConfig { +-webhook : String +} +class SlaSenderMessage { +-id : Long +-workspaceId : Long +-type : String +-name : String +-config : String +} +class SlaConfigMessage { +-id : Long +-type : String +-config : String +} +NotificationConfig <|-- ReceiverConfig : "扩展" +SlaSenderMessage --> NotificationConfig : "包含配置" +SlaConfigMessage --> ReceiverConfig : "解析配置" +``` + +**图示来源** +- [NotificationConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\NotificationConfig.java#L23-L29) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\ReceiverConfig.java#L22-L28) +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSlasHandlerPlugin.java#L79-L95) + +**本节来源** +- [NotificationConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\NotificationConfig.java#L23-L29) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\ReceiverConfig.java#L22-L28) +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSlasHandlerPlugin.java#L79-L95) + +## 消息模板示例 + +### Markdown格式告警信息 +企业微信通知插件主要使用Markdown格式发送告警信息,以下为典型的模板示例: + +```markdown +# [告警主题] + +> 任务执行记录 : [查看详情](https://example.com/detail/123) +> 检查项: 数据质量检查 +> 状态: 失败 +> 时间: 2024-01-01 12:00:00 +> 错误信息: 数据完整性检查未通过 +``` + +### 模板构建规则 +消息模板的构建遵循以下规则: + +1. **标题格式**:使用一级标题(#)显示告警主题 +2. **内容格式**:每条信息使用引用格式(>)显示 +3. **链接处理**:对"任务执行记录"类消息自动创建超链接 +4. **结构化显示**:将JSON格式的消息内容转换为易读的文本格式 + +### 多语言支持 +模板支持中英文双语显示,系统会自动识别消息内容的语言并相应处理: + +- 中文消息:以"任务执行记录"开头的消息 +- 英文消息:以"Task Execution Record"开头的消息 + +对于非特定格式的消息,直接使用引用格式显示原始内容。 + +**本节来源** +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L76-L93) +- [WecomBotConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotConstants.java#L23-L25) + +## API返回结果处理与错误实践 + +### 响应结果处理 +企业微信API的响应结果通过WecomBotRes类进行封装和处理: + +```java +@Data +public class WecomBotRes implements Serializable { + private String errcode; + private String errmsg; + + public boolean success() { + return StringUtils.equalsIgnoreCase(errcode, "0"); + } + + public static WecomBotRes parseFromJson(String json) { + return JSONUtils.parseObject(json, WecomBotRes.class); + } +} +``` + +关键处理逻辑: +- `errcode`为"0"时表示请求成功 +- 使用`success()`方法快速判断请求是否成功 +- 通过`parseFromJson`静态方法解析JSON响应 + +### 错误处理策略 +WecomBotSender实现了完善的错误处理机制: + +1. **异常捕获**:使用try-catch捕获所有异常 +2. **失败记录**:记录发送失败的webhook地址 +3. **日志记录**:详细记录错误信息和请求参数 +4. **结果汇总**:收集所有发送结果并返回 + +### 最佳实践建议 +1. **配置验证**:确保webhook地址正确且不为空 +2. **网络监控**:监控HTTP请求的网络状况 +3. **重试机制**:对于临时性错误考虑实现重试机制 +4. **日志分析**:定期分析错误日志,及时发现和解决问题 +5. **权限检查**:确保企业微信机器人具有发送消息的权限 + +当发送失败时,系统会返回包含失败详情的结果对象,便于上层系统进行相应的处理。 + +```mermaid +flowchart TD +Start([开始发送消息]) --> Validate["验证接收器配置"] +Validate --> EmptyCheck{"接收器为空?"} +EmptyCheck --> |是| ReturnSuccess["返回成功(无接收器)"] +EmptyCheck --> |否| Clean["清理无效配置"] +Clean --> LoopStart["遍历每个接收器"] +LoopStart --> BuildMessage["构建Markdown消息"] +BuildMessage --> PrepareParams["准备API参数"] +PrepareParams --> SendRequest["发送HTTP请求"] +SendRequest --> ParseResponse["解析响应结果"] +ParseResponse --> CheckSuccess{"发送成功?"} +CheckSuccess --> |否| RecordFail["记录失败接收器"] +CheckSuccess --> |是| ContinueLoop +RecordFail --> LogError["记录错误日志"] +LogError --> ContinueLoop +ContinueLoop --> NextReceiver{"还有接收器?"} +NextReceiver --> |是| LoopStart +NextReceiver --> |否| CheckFailures{"有发送失败?"} +CheckFailures --> |是| SetFail["设置状态为失败"] +CheckFailures --> |否| SetSuccess["设置状态为成功"] +SetFail --> ReturnResult["返回结果"] +SetSuccess --> ReturnResult +ReturnSuccess --> ReturnResult +ReturnResult --> End([结束]) +``` + +**图示来源** +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L40-L73) +- [WecomBotRes.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\WecomBotRes.java#L24-L43) + +**本节来源** +- [WecomBotSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\WecomBotSender.java#L40-L73) +- [WecomBotRes.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-wecombot\src\main\java\io\datavines\notification\plugin\wecombot\entity\WecomBotRes.java#L24-L43) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\200\232\347\237\245\346\240\270\345\277\203.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\200\232\347\237\245\346\240\270\345\277\203.md" new file mode 100644 index 00000000..1ade3f29 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\200\232\347\237\245\346\240\270\345\277\203.md" @@ -0,0 +1,293 @@ +# 通知核心 + + +**本文档中引用的文件** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaSenderMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaSenderMessage.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细介绍了Datavines通知系统的核心模块,重点阐述了NotificationManager作为通知系统的中枢,负责协调SLA事件处理和通知分发的职责。文档详细描述了NotificationClient接口及其实现类NotificationClientImpl的设计,包括通知消息的构建、发送和结果反馈机制。同时分析了通知系统的可靠性保障,包括异常处理、重试策略和性能优化。提供了核心组件的配置参数说明和使用示例,并阐述了其与datavines-server模块的集成方式。 + +## 项目结构 +Datavines通知模块采用分层架构设计,主要由API、核心实现和插件三大部分组成。API模块定义了通知系统的核心接口和数据结构,核心模块实现了通知的协调和分发逻辑,插件模块则提供了多种通知渠道的具体实现。 + +```mermaid +graph TD +subgraph "通知API模块" +SlaNotificationMessage["SlaNotificationMessage
通知消息实体"] +SlaSenderMessage["SlaSenderMessage
发送者消息实体"] +SlaConfigMessage["SlaConfigMessage
配置消息实体"] +SlaNotificationResult["SlaNotificationResult
通知结果实体"] +SlasHandlerPlugin["SlasHandlerPlugin
通知处理插件接口"] +end +subgraph "通知核心模块" +NotificationManager["NotificationManager
通知管理器"] +NotificationClient["NotificationClient
通知客户端接口"] +NotificationClientImpl["NotificationClientImpl
通知客户端实现"] +end +subgraph "通知插件模块" +EmailPlugin["EmailSlasHandlerPlugin
邮件通知插件"] +DingTalkPlugin["DingTalkSlasHandlerPlugin
钉钉通知插件"] +LarkPlugin["LarkSlasHandlerPlugin
飞书通知插件"] +WecomBotPlugin["WecomBotSlasHandlerPlugin
企业微信通知插件"] +end +NotificationClientImpl --> NotificationManager +NotificationManager --> SlasHandlerPlugin +EmailPlugin --> SlasHandlerPlugin +DingTalkPlugin --> SlasHandlerPlugin +LarkPlugin --> SlasHandlerPlugin +WecomBotPlugin --> SlasHandlerPlugin +SlaNotificationMessage --> NotificationManager +SlaSenderMessage --> NotificationManager +SlaConfigMessage --> NotificationManager +SlaNotificationResult --> NotificationManager +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaSenderMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaSenderMessage.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java) + +**本节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) + +## 核心组件 +通知系统的核心组件包括NotificationManager、NotificationClient接口及其实现类NotificationClientImpl。NotificationManager作为系统的中枢,负责协调SLA事件的处理和通知分发。NotificationClient提供了统一的接口供外部系统调用,而NotificationClientImpl则是该接口的具体实现,负责与NotificationManager进行交互。 + +**本节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) + +## 架构概述 +Datavines通知系统采用插件化架构设计,通过SPI(Service Provider Interface)机制实现通知渠道的可扩展性。系统核心由NotificationManager组成,负责协调和分发通知请求。外部系统通过NotificationClient接口与通知系统交互,而具体的渠道实现(如邮件、钉钉、飞书等)则通过实现SlasHandlerPlugin接口来完成。 + +```mermaid +sequenceDiagram +participant Application as "应用程序" +participant NotificationClient as "NotificationClient" +participant NotificationManager as "NotificationManager" +participant Plugin as "SlasHandlerPlugin" +Application->>NotificationClient : notify(message, config) +NotificationClient->>NotificationManager : notify(message, config) +NotificationManager->>NotificationManager : 验证配置 +alt 配置有效 +loop 每个通知渠道 +NotificationManager->>Plugin : getOrCreatePlugin(type) +Plugin->>Plugin : notify(message, senderConfig) +Plugin-->>NotificationManager : 返回通知结果 +NotificationManager->>NotificationManager : 合并结果 +end +NotificationManager-->>NotificationClient : 返回汇总结果 +NotificationClient-->>Application : 返回通知结果 +else 配置无效 +NotificationManager-->>NotificationClient : 抛出异常 +NotificationClient-->>Application : 返回错误 +end +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +## 详细组件分析 + +### NotificationManager分析 +NotificationManager是通知系统的核心组件,负责协调SLA事件的处理和通知分发。它在初始化时通过SPI机制加载所有支持的通知插件,并在收到通知请求时,根据配置调用相应的插件进行处理。 + +```mermaid +classDiagram +class NotificationManager { +-Set supportedPlugins ++NotificationManager() ++notify(SlaNotificationMessage, Map>) SlaNotificationResult +} +class SlasHandlerPlugin { +<> ++notify(SlaNotificationMessage, Map>) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class PluginLoader { ++getPluginLoader(Class) PluginLoader ++getSupportedPlugins() Set ++getOrCreatePlugin(String) T +} +NotificationManager --> PluginLoader : "使用" +NotificationManager --> SlasHandlerPlugin : "依赖" +PluginLoader ..> SlasHandlerPlugin : "泛型约束" +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [datavines-spi/PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +**本节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +### NotificationClient分析 +NotificationClient接口及其实现类NotificationClientImpl提供了与通知系统交互的统一入口。该设计采用了门面模式,简化了外部系统与通知系统的集成。 + +```mermaid +classDiagram +class NotificationClient { +<> ++notify(SlaNotificationMessage, Map>) SlaNotificationResult +} +class NotificationClientImpl { +-NotificationManager notificationManager ++notify(SlaNotificationMessage, Map>) SlaNotificationResult +} +class NotificationManager { ++notify(SlaNotificationMessage, Map>) SlaNotificationResult +} +NotificationClientImpl --> NotificationManager : "依赖" +NotificationClient <|.. NotificationClientImpl : "实现" +``` + +**图示来源** +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +**本节来源** +- [NotificationClient.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) + +### 通知消息实体分析 +通知系统定义了一系列实体类来封装通知相关的数据,包括通知消息、发送者配置、接收者配置和通知结果等。 + +```mermaid +classDiagram +class SlaNotificationMessage { +-Long slaId +-String subject +-String message +} +class SlaSenderMessage { +-Long id +-Long workspaceId +-String type +-String name +-String config +} +class SlaConfigMessage { +-Long id +-String type +-String config +} +class SlaNotificationResult { +-Boolean status +-List records ++merge(SlaNotificationResult) SlaNotificationResult +} +class SlaNotificationResultRecord { +-Boolean status +-String message +} +SlaNotificationResult --> SlaNotificationResultRecord : "包含" +``` + +**图示来源** +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaSenderMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaSenderMessage.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java) +- [SlaNotificationResultRecord.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResultRecord.java) + +**本节来源** +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaSenderMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaSenderMessage.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java) + +## 依赖分析 +通知系统通过SPI机制实现插件化扩展,核心模块依赖于API模块定义的接口和实体,而具体的渠道实现则作为独立的插件模块存在。 + +```mermaid +graph TD +NotificationClientImpl --> NotificationManager +NotificationManager --> PluginLoader +PluginLoader --> SlasHandlerPlugin +EmailPlugin --> SlasHandlerPlugin +DingTalkPlugin --> SlasHandlerPlugin +LarkPlugin --> SlasHandlerPlugin +WecomBotPlugin --> SlasHandlerPlugin +NotificationClientImpl -.-> SlaNotificationMessage +NotificationClientImpl -.-> SlaSenderMessage +NotificationClientImpl -.-> SlaConfigMessage +NotificationClientImpl -.-> SlaNotificationResult +style NotificationClientImpl fill:#f9f,stroke:#333 +style NotificationManager fill:#f9f,stroke:#333 +style PluginLoader fill:#bbf,stroke:#333 +style SlasHandlerPlugin fill:#bbf,stroke:#333 +style EmailPlugin fill:#9f9,stroke:#333 +style DingTalkPlugin fill:#9f9,stroke:#333 +style LarkPlugin fill:#9f9,stroke:#333 +style WecomBotPlugin fill:#9f9,stroke:#333 +``` + +**图示来源** +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) + +**本节来源** +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +## 性能考虑 +通知系统在设计时考虑了性能和可靠性,通过以下机制确保系统的高效运行: + +1. **异步处理**:虽然当前实现为同步调用,但架构支持异步处理模式,可通过消息队列实现通知的异步发送。 +2. **批量处理**:系统支持批量发送通知,减少网络开销和系统负载。 +3. **连接池**:对于需要建立网络连接的通知渠道(如邮件),建议使用连接池技术复用连接。 +4. **缓存机制**:常用配置信息可以缓存,减少重复解析的开销。 +5. **并发处理**:不同通知渠道可以并行处理,提高整体处理效率。 + +## 故障排除指南 +当通知系统出现问题时,可以按照以下步骤进行排查: + +1. **检查配置**:确保通知渠道的配置正确无误,特别是认证信息和网络设置。 +2. **查看日志**:检查系统日志,定位具体的错误信息和堆栈跟踪。 +3. **验证网络**:确保服务器能够访问通知服务的API端点。 +4. **测试连接**:使用简单的测试程序验证与通知服务的连接是否正常。 +5. **检查权限**:确认应用有足够的权限发送通知。 + +**本节来源** +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) + +## 结论 +Datavines通知系统通过清晰的分层架构和插件化设计,实现了灵活、可扩展的通知功能。NotificationManager作为系统中枢,有效地协调了SLA事件的处理和通知分发。通过NotificationClient接口,外部系统可以方便地集成通知功能。系统的可靠性通过完善的异常处理和结果反馈机制得到保障。未来可以进一步优化性能,如引入异步处理机制和更智能的重试策略。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\202\256\344\273\266\351\200\232\347\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\202\256\344\273\266\351\200\232\347\237\245.md" new file mode 100644 index 00000000..682c047b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\202\256\344\273\266\351\200\232\347\237\245.md" @@ -0,0 +1,170 @@ +# 邮件通知 + + +**本文档引用的文件** +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [EMailSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java) +- [NotificationConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/entity/NotificationConfig.java) +- [ReceiverConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/entity/ReceiverConfig.java) +- [EmailConstants.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailConstants.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [故障排除指南](#故障排除指南) + +## 简介 +本文档详细介绍了DataVines平台中邮件通知插件的实现机制。重点阐述了`EmailSlasHandlerPlugin`如何集成到通知系统中,处理SLA告警并调用邮件发送功能。文档深入分析了`EMailSender`的实现细节,包括JavaMail API的使用、SMTP服务器配置、邮件内容(HTML/文本)构建和附件处理。同时,对`NotificationConfig`配置实体进行了全面解析,涵盖SMTP主机、端口、认证信息、发件人/收件人列表等关键参数。此外,还提供了邮件模板配置、SSL/TLS安全连接设置和实际使用示例,以及邮件发送失败的常见原因和解决方案。 + +## 核心组件 +本节分析邮件通知系统的核心组件,包括`EmailSlasHandlerPlugin`、`EMailSender`和相关的配置实体。 + +**组件来源** +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [EMailSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java) +- [ReceiverConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/entity/ReceiverConfig.java) + +## 架构概述 +邮件通知系统采用插件化架构,通过SPI(Service Provider Interface)机制实现可扩展性。`NotificationManager`作为核心协调者,负责加载和管理所有通知插件。当需要发送SLA告警时,`NotificationClientImpl`会调用`NotificationManager`,后者根据配置的发送器类型(如email、dingtalk等)动态加载相应的`SlasHandlerPlugin`实现。 + +```mermaid +graph TD +A[通知客户端 NotificationClientImpl] --> B[通知管理器 NotificationManager] +B --> C[插件加载器 PluginLoader] +C --> D[EmailSlasHandlerPlugin] +C --> E[DingTalkSlasHandlerPlugin] +C --> F[LarkSlasHandlerPlugin] +D --> G[EMailSender] +E --> H[DingTalkSender] +F --> I[LarkSender] +J[SLA告警消息] --> A +G --> K[SMTP服务器] +``` + +**图表来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) + +## 详细组件分析 + +### EmailSlasHandlerPlugin分析 +`EmailSlasHandlerPlugin`是邮件通知插件的核心实现类,实现了`SlasHandlerPlugin`接口。它负责处理SLA告警消息,解析收件人配置,并调用`EMailSender`发送邮件。 + +#### 配置JSON生成 +`EmailSlasHandlerPlugin`提供了两个方法来生成配置JSON:`getConfigSenderJson`和`getConfigJson`。前者用于生成发送器(SMTP服务器)的配置,后者用于生成接收者的配置。 + +```mermaid +classDiagram +class EmailSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +-getInputParam(String, String, String, int, Validate) InputParam +-getInputParamNoValidate(String, String, String, int) InputParam +} +EmailSlasHandlerPlugin ..|> SlasHandlerPlugin +``` + +**图表来源** +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +### EMailSender分析 +`EMailSender`是邮件发送的核心类,封装了JavaMail API的使用细节,负责与SMTP服务器通信并发送邮件。 + +#### 邮件发送流程 +`EMailSender`的邮件发送流程包括:创建邮件会话、设置发件人和收件人、构建邮件内容、发送邮件等步骤。 + +```mermaid +sequenceDiagram +participant Client as "通知客户端" +participant Plugin as "EmailSlasHandlerPlugin" +participant Sender as "EMailSender" +participant SMTP as "SMTP服务器" +Client->>Plugin : notify(slaNotificationMessage, config) +Plugin->>Sender : new EMailSender(senderMessage) +Plugin->>Sender : sendMails(receiverSet, copyReceiverSet, subject, message) +Sender->>Sender : getSession() +Sender->>Sender : setMailSession(session) +Sender->>Sender : setFrom(mailSenderEmail) +Sender->>Sender : addTo(receiver) +Sender->>Sender : addCc(receiverCc) +Sender->>Sender : setMsg(textMessageContent) +Sender->>Sender : setSubject(subject) +Sender->>SMTP : send() +SMTP-->>Sender : 发送结果 +Sender-->>Plugin : SlaNotificationResultRecord +Plugin-->>Client : SlaNotificationResult +``` + +**图表来源** +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [EMailSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java) + +#### 邮件内容构建 +`EMailSender`通过`getTextTypeMessage`方法将JSON格式的消息内容转换为HTML表格格式的邮件正文。该方法使用`EmailConstants`中定义的HTML标签常量来构建结构化的邮件内容。 + +```mermaid +flowchart TD +Start([开始]) --> ParseJSON["解析JSON消息内容"] +ParseJSON --> Loop["遍历每个消息节点"] +Loop --> FormatNode["格式化消息节点"] +FormatNode --> CheckLink{"是否为任务执行记录?"} +CheckLink --> |是| FormatLink["创建超链接"] +CheckLink --> |否| NormalText["普通文本"] +FormatLink --> AddToContent["添加到内容构建器"] +NormalText --> AddToContent +AddToContent --> NextNode["下一个节点"] +NextNode --> EndLoop{"所有节点处理完毕?"} +EndLoop --> |否| Loop +EndLoop --> |是| WrapHTML["包裹HTML头尾"] +WrapHTML --> Return["返回HTML内容"] +Return --> End([结束]) +``` + +**图表来源** +- [EMailSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java) +- [EmailConstants.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailConstants.java) + +## 依赖分析 +邮件通知插件依赖于多个外部库和内部模块,通过Maven进行依赖管理。 + +```mermaid +graph TD +A[邮件通知插件] --> B[commons-collections4] +A --> C[poi & poi-ooxml] +A --> D[guava] +A --> E[logback-classic] +A --> F[slf4j-api] +A --> G[commons-email] +A --> H[javax.mail] +A --> I[datavines-common] +A --> J[datavines-notification-api] +``` + +**图表来源** +- [pom.xml](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/pom.xml) + +## 故障排除指南 +本节提供邮件发送失败的常见原因和解决方案。 + +### 常见问题及解决方案 +| 问题现象 | 可能原因 | 解决方案 | +|---------|---------|---------| +| 连接超时 | SMTP主机或端口配置错误 | 检查`serverHost`和`serverPort`配置 | +| 认证失败 | 用户名或密码错误 | 检查`user`和`passwd`配置 | +| SSL/TLS连接失败 | 安全设置不匹配 | 检查`starttlsEnable`、`sslEnable`和`smtpSslTrust`配置 | +| 邮件被拒绝 | 发件人邮箱未验证 | 确保`sender`邮箱已在SMTP服务器验证 | +| 附件发送失败 | 附件路径错误或权限不足 | 检查附件文件路径和读取权限 | + +**组件来源** +- [EMailSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\222\211\351\222\211\351\200\232\347\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\222\211\351\222\211\351\200\232\347\237\245.md" new file mode 100644 index 00000000..64f69eb8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\222\211\351\222\211\351\200\232\347\237\245.md" @@ -0,0 +1,294 @@ +# 钉钉通知 + + +**本文档引用的文件** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\ReceiverConfig.java) +- [NotificationConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\NotificationConfig.java) +- [DingTalkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkConstants.java) +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java) +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 简介 +本文档详细介绍了DataVines平台中钉钉通知插件的实现机制。该插件作为SPI(Service Provider Interface)实现,用于处理SLA(Service Level Agreement)事件并触发钉钉消息通知。文档将深入分析`DingTalkSlasHandlerPlugin`作为SPI实现的处理流程,`DingTalkSender`的消息发送实现,以及`NotificationConfig`配置实体的结构和参数。同时,文档还将提供钉钉通知的卡片消息模板设计、自定义消息内容配置和实际使用示例。 + +## 核心组件 +钉钉通知插件的核心组件包括`DingTalkSlasHandlerPlugin`、`DingTalkSender`和`ReceiverConfig`等类。`DingTalkSlasHandlerPlugin`实现了`SlasHandlerPlugin` SPI接口,负责处理SLA事件并调用`DingTalkSender`发送消息。`DingTalkSender`类封装了与钉钉Webhook API交互的逻辑,包括消息格式构建、安全签名计算和HTTP请求发送。`ReceiverConfig`类定义了接收者配置,包括Webhook地址、安全密钥、@提及的手机号等参数。 + +**本节来源** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\ReceiverConfig.java) + +## 架构概述 +钉钉通知插件的架构基于SPI机制,实现了松耦合的设计。`NotificationManager`作为通知系统的入口,通过`PluginLoader`加载所有实现了`SlasHandlerPlugin`接口的插件。当需要发送通知时,`NotificationManager`会根据配置的发送器类型找到对应的插件实例,并调用其`notify`方法。`DingTalkSlasHandlerPlugin`作为钉钉通知的具体实现,负责解析配置、构建消息并调用`DingTalkSender`完成实际的消息发送。 + +```mermaid +graph TD +A[NotificationManager] --> B[PluginLoader] +B --> C[SlasHandlerPlugin] +C --> D[DingTalkSlasHandlerPlugin] +D --> E[DingTalkSender] +E --> F[钉钉Webhook API] +G[SLA事件] --> A +``` + +**图表来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) + +## 详细组件分析 + +### DingTalkSlasHandlerPlugin分析 +`DingTalkSlasHandlerPlugin`是钉钉通知功能的核心实现类,它实现了`SlasHandlerPlugin` SPI接口。该类的主要职责是处理SLA通知消息,根据配置调用`DingTalkSender`发送钉钉消息。 + +#### 类图 +```mermaid +classDiagram +class SlasHandlerPlugin { +<> ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class DingTalkSlasHandlerPlugin { +-log Logger ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class DingTalkSender { +-msgType String ++sendCardMsg(Set, String, String) SlaNotificationResultRecord +-generateMsgJson(String, String, ReceiverConfig) String +-constructUrl(String, String) String +-constructHttpPost(String, String) HttpPost +-getDefaultClient() CloseableHttpClient +} +class ReceiverConfig { ++webhook String ++secret String ++keyword String ++atMobiles String ++atDingtalkIds String ++isAtAll Boolean ++equals(Object) boolean ++hashCode() int +} +SlasHandlerPlugin <|-- DingTalkSlasHandlerPlugin +DingTalkSlasHandlerPlugin --> DingTalkSender : "使用" +DingTalkSlasHandlerPlugin --> ReceiverConfig : "使用" +DingTalkSender --> ReceiverConfig : "使用" +``` + +**图表来源** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\ReceiverConfig.java) +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java) + +#### 通知流程序列图 +```mermaid +sequenceDiagram +participant NotificationManager +participant DingTalkSlasHandlerPlugin +participant DingTalkSender +participant DingTalkAPI +NotificationManager->>DingTalkSlasHandlerPlugin : notify(message, config) +DingTalkSlasHandlerPlugin->>DingTalkSlasHandlerPlugin : 过滤钉钉发送器 +DingTalkSlasHandlerPlugin->>DingTalkSender : new DingTalkSender() +DingTalkSlasHandlerPlugin->>DingTalkSlasHandlerPlugin : 解析ReceiverConfig +DingTalkSlasHandlerPlugin->>DingTalkSender : sendCardMsg(config, subject, message) +DingTalkSender->>DingTalkSender : generateMsgJson() +DingTalkSender->>DingTalkSender : constructUrl() +DingTalkSender->>DingTalkSender : constructHttpPost() +DingTalkSender->>DingTalkAPI : execute(httpPost) +DingTalkAPI-->>DingTalkSender : 返回响应 +DingTalkSender-->>DingTalkSlasHandlerPlugin : 返回发送结果 +DingTalkSlasHandlerPlugin-->>NotificationManager : 返回通知结果 +``` + +**图表来源** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) + +**本节来源** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) + +### DingTalkSender实现分析 +`DingTalkSender`类负责实现与钉钉Webhook API的具体交互,包括消息构建、安全签名计算和HTTP请求发送。 + +#### 消息发送流程图 +```mermaid +flowchart TD +Start([开始]) --> ValidateInput["验证接收者配置"] +ValidateInput --> InputValid{"配置为空?"} +InputValid --> |是| ReturnSuccess["返回成功"] +InputValid --> |否| SetClassLoader["设置类加载器"] +SetClassLoader --> InitializeFailSet["初始化失败接收者集合"] +InitializeFailSet --> LoopStart["遍历每个接收者配置"] +LoopStart --> GenerateMsg["生成消息JSON"] +GenerateMsg --> ConstructUrl["构造带签名的URL"] +ConstructUrl --> CreateHttpPost["创建HttpPost请求"] +CreateHttpPost --> ExecuteRequest["执行HTTP请求"] +ExecuteRequest --> HandleResponse["处理响应"] +HandleResponse --> LogResponse["记录响应日志"] +LogResponse --> CheckException{"发生异常?"} +CheckException --> |是| AddToFailSet["添加到失败集合"] +CheckException --> |否| ContinueLoop +AddToFailSet --> ContinueLoop["继续下一个配置"] +ContinueLoop --> LoopEnd{"所有配置处理完毕?"} +LoopEnd --> |否| LoopStart +LoopEnd --> |是| CheckFailSet{"失败集合为空?"} +CheckFailSet --> |否| FormatFailMessage["格式化失败消息"] +CheckFailSet --> |是| SetSuccessStatus["设置成功状态"] +FormatFailMessage --> SetFailStatus["设置失败状态"] +SetFailStatus --> End([结束]) +SetSuccessStatus --> End +ReturnSuccess --> End +``` + +**图表来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) + +#### 消息格式构建分析 +`DingTalkSender`的`generateMsgJson`方法负责构建符合钉钉API要求的消息JSON。该方法支持两种消息类型:文本(text)和Markdown。消息内容根据接收者配置中的参数动态构建,包括标题、内容、关键词和@提及信息。 + +```mermaid +flowchart TD +Start([开始]) --> CheckMsgType{"消息类型为空?"} +CheckMsgType --> |是| SetDefaultType["设置默认为文本类型"] +SetDefaultType --> CreateItemsMap["创建消息项Map"] +CreateItemsMap --> AddMsgType["添加消息类型"] +AddMsgType --> CreateTextMap["创建文本Map"] +CreateTextMap --> AddTextToItems["将文本Map添加到消息项"] +AddTextToItems --> CheckMarkdown{"Markdown类型?"} +CheckMarkdown --> |是| BuildMarkdownContent["构建Markdown内容"] +CheckMarkdown --> |否| BuildTextContent["构建文本内容"] +BuildMarkdownContent --> AddTitle["添加标题"] +BuildMarkdownContent --> AddKeyword["添加关键词"] +BuildMarkdownContent --> AddAtMentions["添加@提及"] +BuildTextContent --> AddContent["添加内容"] +BuildTextContent --> AddKeyword["添加关键词"] +AddAtMentions --> CreateAtMap["创建@提及Map"] +AddKeyword --> CreateAtMap +CreateAtMap --> AddAtMobiles["添加手机号"] +AddAtMobiles --> AddAtDingtalkIds["添加钉钉ID"] +AddAtDingtalkIds --> AddIsAtAll["添加是否@所有人"] +AddIsAtAll --> AddAtToItems["将@提及Map添加到消息项"] +AddAtToItems --> ConvertToJson["转换为JSON字符串"] +ConvertToJson --> End([结束]) +``` + +**图表来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) + +**本节来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) + +### NotificationConfig配置实体分析 +`NotificationConfig`和`ReceiverConfig`类定义了钉钉通知的配置参数。`ReceiverConfig`是主要的配置实体,包含了与钉钉Webhook交互所需的所有参数。 + +#### 配置参数表 +| 参数名称 | 参数说明 | 是否必填 | 默认值 | 安全验证 | +|--------|--------|--------|--------|--------| +| webhook | 钉钉群机器人Webhook地址 | 是 | 无 | IP白名单 | +| secret | 加签密钥 | 否 | 无 | HmacSHA256签名 | +| keyword | 关键词 | 否 | 无 | 需在机器人安全设置中配置 | +| atMobiles | @提及的手机号 | 否 | 无 | 需群成员手机号 | +| atDingtalkIds | @提及的钉钉ID | 否 | 无 | 需群成员钉钉ID | +| isAtAll | 是否@所有人 | 是 | FALSE | 需群管理员权限 | + +**图表来源** +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\ReceiverConfig.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) + +#### 安全验证机制 +钉钉通知支持多种安全验证机制,包括加签、IP白名单和关键词验证。`DingTalkSender`的`constructUrl`方法实现了加签机制,通过HmacSHA256算法计算签名,并将签名和时间戳拼接到Webhook URL上。 + +```mermaid +flowchart TD +Start([开始]) --> CheckSecret{"密钥为空?"} +CheckSecret --> |是| ReturnWebhook["直接返回Webhook地址"] +CheckSecret --> |否| GetTimestamp["获取当前时间戳"] +GetTimestamp --> CreateStringToSign["创建待签名字符串"] +CreateStringToSign --> InitMac["初始化HmacSHA256"] +InitMac --> ComputeSign["计算签名"] +ComputeSign --> EncodeSign["URL编码签名"] +EncodeSign --> ConstructFinalUrl["构造最终URL"] +ConstructFinalUrl --> End([结束]) +``` + +**图表来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) + +**本节来源** +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\ReceiverConfig.java) +- [DingTalkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkConstants.java) + +## 依赖分析 +钉钉通知插件依赖于多个核心模块和第三方库。通过分析pom.xml文件,可以了解其依赖关系。 + +```mermaid +graph TD +A[钉钉通知插件] --> B[commons-collections4] +A --> C[guava] +A --> D[logback-classic] +A --> E[slf4j-api] +A --> F[datavines-common] +A --> G[datavines-notification-api] +F --> H[核心工具类] +G --> I[通知API] +I --> J[SlasHandlerPlugin] +``` + +**图表来源** +- [pom.xml](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\pom.xml) +- [datavines-common](file://datavines-common) +- [datavines-notification-api](file://datavines-notification\datavines-notification-api) + +**本节来源** +- [pom.xml](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\pom.xml) + +## 性能考虑 +钉钉通知插件在设计时考虑了性能和可靠性。`DingTalkSender`使用Apache HttpClient进行HTTP通信,并在每次发送后正确关闭连接。消息发送采用同步方式,确保消息按顺序发送。对于多个接收者,插件会逐个尝试发送,并记录失败的接收者,避免单个失败影响整体通知。 + +## 故障排除指南 +### 常见问题及解决方案 +1. **消息发送失败,返回310000错误** + - 问题原因:未正确添加签名参数 + - 解决方案:确保在启用加签时,`constructUrl`方法正确计算并添加了sign和timestamp参数 + +2. **无法@提及群成员** + - 问题原因:手机号或钉钉ID格式不正确 + - 解决方案:检查`atMobiles`和`atDingtalkIds`参数格式,多个ID用逗号分隔 + +3. **消息内容乱码** + - 问题原因:字符编码问题 + - 解决方案:确保在`generateMsgJson`方法中正确使用UTF-8编码处理字符串 + +4. **连接超时** + - 问题原因:网络问题或钉钉API响应慢 + - 解决方案:检查网络连接,考虑增加HTTP客户端的超时设置 + +**本节来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) + +## 结论 +钉钉通知插件通过SPI机制实现了灵活的通知功能,能够有效处理SLA事件并发送钉钉消息。插件设计考虑了安全性、可靠性和易用性,支持多种消息格式和安全验证机制。通过`DingTalkSlasHandlerPlugin`和`DingTalkSender`的协作,实现了从事件处理到消息发送的完整流程。未来可以考虑增加异步发送、消息队列支持和更丰富的消息模板等功能,进一步提升通知系统的性能和用户体验。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\243\236\344\271\246\351\200\232\347\237\245.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\243\236\344\271\246\351\200\232\347\237\245.md" new file mode 100644 index 00000000..4661292b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-notification\346\250\241\345\235\227/\351\243\236\344\271\246\351\200\232\347\237\245.md" @@ -0,0 +1,261 @@ +# 飞书通知 + + +**本文档引用文件** +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) +- [LarkSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSender.java) +- [CardDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/CardDTO.java) +- [GroupCardDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/GroupCardDTO.java) +- [MessageDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/MessageDTO.java) +- [ReceiverConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/ReceiverConfig.java) +- [ContentUtil.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/util/ContentUtil.java) +- [LarkConstants.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkConstants.java) +- [ElementDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/card/ElementDTO.java) +- [HeaderDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/card/HeaderDTO.java) +- [TextDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/card/TextDTO.java) +- [TitleDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/card/TitleDTO.java) +- [io.datavines.notification.api.spi.SlasHandlerPlugin](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/resources/META-INF/plugins/io.datavines.notification.api.spi.SlasHandlerPlugin) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [SPI接口实现](#spi接口实现) +4. [消息发送机制](#消息发送机制) +5. [数据结构设计](#数据结构设计) +6. [消息内容组织](#消息内容组织) +7. [飞书Webhook配置](#飞书webhook配置) +8. [错误处理与响应](#错误处理与响应) + +## 简介 +飞书通知插件是DataVines系统中的一个重要组件,用于在数据质量监控过程中触发SLA事件时向飞书群组发送告警消息。该插件通过实现SPI接口,支持飞书卡片消息(Card)的构建与发送,具备灵活的配置选项和可扩展的消息模板设计。 + +## 核心组件 + +飞书通知插件的核心由以下几个关键类构成: +- `LarkSlasHandlerPlugin`:实现SPI接口,处理SLA事件并调用发送器 +- `LarkSender`:负责实际的飞书消息发送逻辑 +- `CardDTO`及其子类:定义飞书卡片消息的数据结构 +- `MessageDTO`:封装消息内容的标题与正文 +- `ReceiverConfig`:存储接收方配置信息,如Webhook地址和@所有人设置 + +**核心组件来源** +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) +- [LarkSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSender.java) +- [CardDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/CardDTO.java) +- [MessageDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/MessageDTO.java) +- [ReceiverConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/ReceiverConfig.java) + +## SPI接口实现 + +`LarkSlasHandlerPlugin`类实现了`SlasHandlerPlugin`接口,作为服务提供者接口(SPI)的实现类,负责处理SLA告警事件。 + +该类通过`notify`方法接收告警消息和配置信息,筛选出类型为"lark"的通知渠道,并为每个飞书接收组创建`LarkSender`实例进行消息发送。 + +插件还提供了`getConfigJson`方法,定义了飞书通知所需的配置参数,包括: +- `webhook`:飞书群机器人Webhook地址 +- `atAll`:是否@所有人,支持"是"和"否"两个选项 + +插件通过`META-INF/plugins/io.datavines.notification.api.spi.SlasHandlerPlugin`文件注册,内容为`lark=io.datavines.notification.plugin.lark.LarkSlasHandlerPlugin`,实现了SPI机制的自动发现。 + +```mermaid +classDiagram +class SlasHandlerPlugin { +<> ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class LarkSlasHandlerPlugin { +-log Logger ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +LarkSlasHandlerPlugin --|> SlasHandlerPlugin : 实现 +note right of LarkSlasHandlerPlugin +实现SPI接口,处理飞书告警 +- 通过webhook发送消息 +- 支持@所有人功能 +- 配置JSON生成 +end note +``` + +**图示来源** +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) +- [io.datavines.notification.api.spi.SlasHandlerPlugin](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/resources/META-INF/plugins/io.datavines.notification.api.spi.SlasHandlerPlugin) + +## 消息发送机制 + +`LarkSender`类负责具体的飞书消息发送逻辑。其核心方法`sendCardMsg`接收接收者配置集合、消息主题和内容,构建并发送飞书卡片消息。 + +发送流程如下: +1. 检查接收者集合是否为空,若为空则直接返回 +2. 为每个接收者配置创建消息列表 +3. 根据配置决定是否添加@所有人消息 +4. 构建`GroupCardDTO`卡片对象 +5. 使用`ContentUtil`创建请求参数映射 +6. 通过HTTP POST请求发送到飞书Webhook + +消息发送采用线程安全的方式,设置当前线程的类加载器以确保类路径正确。发送失败时会记录失败的接收者,并在最终结果中返回错误信息。 + +```mermaid +sequenceDiagram +participant Plugin as LarkSlasHandlerPlugin +participant Sender as LarkSender +participant Util as ContentUtil +participant HTTP as HttpUtils +participant Feishu as 飞书API +Plugin->>Sender : sendCardMsg(receiverSet, subject, message) +Sender->>Sender : 检查接收者集合 +loop 每个接收者 +Sender->>Sender : 创建消息列表 +alt 需要@所有人 +Sender->>MessageDTO : atAllBuilder() +end +Sender->>GroupCardDTO : new GroupCardDTO() +Sender->>Util : createParamMap() +Util-->>Sender : paramMap +Sender->>HTTP : post(webhook, jsonData) +HTTP->>Feishu : 发送POST请求 +Feishu-->>HTTP : 响应结果 +HTTP-->>Sender : 响应 +end +Sender-->>Plugin : SlaNotificationResult +``` + +**图示来源** +- [LarkSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSender.java) +- [ContentUtil.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/util/ContentUtil.java) + +## 数据结构设计 + +飞书通知插件采用分层的数据结构设计来构建卡片消息。 + +`CardDTO`是抽象基类,定义了卡片的基本结构,包含: +- `header`:卡片头部,类型为`HeaderDTO` +- `elements`:元素列表,类型为`ElementDTO`数组 + +`GroupCardDTO`继承自`CardDTO`,提供具体的构造函数实现。 + +`HeaderDTO`包含: +- `template`:头部模板颜色 +- `title`:标题对象,类型为`TitleDTO` + +`ElementDTO`表示卡片中的每个元素,包含: +- `text`:文本内容,类型为`TextDTO` +- `tag`:元素标签,固定为"div" + +`TextDTO`和`TitleDTO`结构相似,都包含`content`和`tag`两个字段,分别表示内容文本和内容类型。 + +```mermaid +classDiagram +class CardDTO { +-header HeaderDTO +-elements ElementDTO[] ++CardDTO() ++CardDTO(headerContent, headerColor, messageList) +} +class GroupCardDTO { ++GroupCardDTO() ++GroupCardDTO(headerContent, headerColor, messageList) +} +class HeaderDTO { +-template String +-title TitleDTO +} +class ElementDTO { +-text TextDTO +-tag String +} +class TextDTO { +-content String +-tag String +} +class TitleDTO { +-content String +-tag String +} +CardDTO <|-- GroupCardDTO : 继承 +CardDTO --> HeaderDTO : 包含 +CardDTO --> ElementDTO : 包含多个 +HeaderDTO --> TitleDTO : 包含 +ElementDTO --> TextDTO : 包含 +``` + +**图示来源** +- [CardDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/CardDTO.java) +- [GroupCardDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/GroupCardDTO.java) +- [HeaderDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/card/HeaderDTO.java) +- [ElementDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/card/ElementDTO.java) +- [TextDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/card/TextDTO.java) +- [TitleDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/card/TitleDTO.java) + +## 消息内容组织 + +消息内容通过`MessageDTO`类进行组织,该类使用Builder模式提供了多种静态工厂方法来创建不同类型的消息: + +- `routineBuilder`:创建常规消息,包含标题和普通内容 +- `atBuilder`:创建@指定用户的消息 +- `atAllBuilder`:创建@所有人的消息 +- `atListBuilder`:创建@用户列表的消息 + +在`CardDTO`的构造函数中,这些`MessageDTO`对象会被转换为飞书卡片的元素。每个消息的标题会以加粗形式显示(使用`**`标记),后跟中文冒号,然后是消息内容。 + +卡片头部使用预定义的标题"【数据质量告警】"和红色模板,通过`alarmTitle`和`alarmColor`字段配置。 + +消息内容采用飞书的lark_md格式,支持基本的Markdown语法,使消息呈现更加清晰和结构化。 + +```mermaid +flowchart TD +Start([开始]) --> CreateMessages["创建MessageDTO列表"] +CreateMessages --> AddRoutine["添加常规消息\nroutineBuilder(摘要, subject)"] +AddRoutine --> AddRoutine2["添加常规消息\nroutineBuilder(详情, message)"] +AddRoutine2 --> CheckAtAll{"是否@所有人?"} +CheckAtAll --> |是| AddAtAll["添加@所有人消息\natAllBuilder(请留意)"] +CheckAtAll --> |否| SkipAtAll[跳过] +AddAtAll --> BuildCard["构建GroupCardDTO"] +SkipAtAll --> BuildCard +BuildCard --> CreateParam["创建请求参数"] +CreateParam --> SendHTTP["发送HTTP POST请求"] +SendHTTP --> End([结束]) +``` + +**图示来源** +- [MessageDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/MessageDTO.java) +- [CardDTO.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/CardDTO.java) +- [LarkSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSender.java) + +## 飞书Webhook配置 + +飞书通知插件通过Webhook机制与飞书API进行通信。配置主要包括以下参数: + +- **Webhook URL**:飞书群机器人的Webhook地址,用于发送消息 +- **@所有人**:布尔值,决定是否在消息中@群内所有成员 + +Webhook URL的格式为`https://open.feishu.cn/open-apis/bot/v2/hook/{token}`,其中`token`是飞书机器人生成的唯一标识。 + +在代码中,这些配置通过`ReceiverConfig`类进行管理,包含`groupName`、`webhook`和`atAll`三个字段。配置信息以JSON格式存储,并在发送消息时解析。 + +插件使用`LarkConstants`类定义了飞书API的相关常量,包括消息类型(interactive)、消息体字段名(msg_type, card)等,确保与飞书API的兼容性。 + +**配置来源** +- [ReceiverConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/ReceiverConfig.java) +- [LarkConstants.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkConstants.java) +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) + +## 错误处理与响应 + +插件实现了完善的错误处理机制,确保在发送失败时能够提供有用的反馈信息。 + +`LarkSender`在发送消息时使用try-catch块捕获所有异常,将发送失败的接收者添加到`failToReceivers`集合中。发送完成后,如果存在失败的接收者,会构造包含失败组名的错误消息,并将结果状态设置为false。 + +`SlaNotificationResult`对象包含整体状态和详细的记录列表,每个记录对应一个通知渠道的发送结果。这种设计使得系统能够精确地追踪每个告警的发送状态。 + +HTTP请求使用`HttpUtils.post`方法发送,该方法会处理底层的网络通信。虽然当前代码没有显式处理飞书API的特定错误码,但通过捕获异常和记录错误日志,为后续的错误码处理提供了基础。 + +日志记录使用SLF4J框架,错误信息会包含完整的异常堆栈,便于问题排查和系统监控。 + +**错误处理来源** +- [LarkSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSender.java) +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/MySQL\346\263\250\345\206\214\344\270\255\345\277\203.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/MySQL\346\263\250\345\206\214\344\270\255\345\277\203.md" new file mode 100644 index 00000000..3f387526 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/MySQL\346\263\250\345\206\214\344\270\255\345\277\203.md" @@ -0,0 +1,296 @@ +# MySQL注册中心 + + +**本文引用的文件列表** +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) +- [RegistryLock.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/RegistryLock.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [Stopper.java](file://datavines-common/src/main/java/io/datavines/common/utils/Stopper.java) +- [io.datavines.registry.api.Registry](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/resources/META-INF/plugins/io.datavines.registry.api.Registry) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [组件详解](#组件详解) +6. [依赖关系分析](#依赖关系分析) +7. [性能与可靠性特性](#性能与可靠性特性) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录:数据库表结构与配置](#附录数据库表结构与配置) + +## 简介 +本文件系统性阐述基于MySQL实现的注册中心,重点说明MysqlRegistry如何通过数据库完成服务注册与发现、心跳与租约管理、节点状态同步,以及分布式锁(MysqlMutex与RegistryLock)的工作原理。同时给出数据库表结构、配置要点、使用建议与常见问题排查方法,帮助读者快速理解并安全地在生产环境中部署与运维。 + +## 项目结构 +MySQL注册中心位于“datavines-registry-plugins/datavines-registry-mysql”模块,核心代码围绕三个关键类展开: +- MysqlRegistry:对外暴露的注册中心实现,聚合分布式锁与节点状态管理能力 +- MysqlMutex:基于数据库的分布式互斥锁,负责锁的申请、续期与过期清理 +- MysqlServerStateManager:基于数据库的服务节点注册与发现,负责心跳、节点存活检测与事件通知 + +```mermaid +graph TB +subgraph "注册中心插件(mysql)" +MR["MysqlRegistry"] +MM["MysqlMutex"] +MSSM["MysqlServerStateManager"] +RL["RegistryLock"] +end +subgraph "注册中心API" +REG["Registry 接口"] +SI["ServerInfo"] +end +MR --> REG +MR --> MM +MR --> MSSM +MSSM --> SI +MM --> RL +``` + +图表来源 +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L1-L107) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) +- [RegistryLock.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/RegistryLock.java#L1-L36) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L1-L44) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java#L1-L49) + +章节来源 +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L1-L107) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L1-L44) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java#L1-L49) + +## 核心组件 +- MysqlRegistry:实现Registry接口,负责初始化数据库连接、持有MysqlMutex与MysqlServerStateManager实例,并将上层调用委托给这两个组件;提供订阅/取消订阅、获取活跃节点列表、关闭资源等能力。 +- MysqlMutex:基于数据库的分布式锁,支持按key申请锁、定时续期、过期清理;内部维护“持有锁”的本地映射,避免重复加锁。 +- MysqlServerStateManager:基于数据库的节点注册与发现,周期性发送心跳、定期检查节点存活、对比新旧节点集合触发ADD/REMOVE事件通知。 +- RegistryLock:锁持有者的轻量数据模型,包含锁键、持有者地址与更新时间。 +- ServerInfo:节点信息模型,包含主机、端口、创建/更新时间及统一地址格式。 + +章节来源 +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L1-L107) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) +- [RegistryLock.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/RegistryLock.java#L1-L36) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java#L1-L49) + +## 架构总览 +MySQL注册中心通过两套机制协同工作: +- 分布式锁:基于表dv_registry_lock实现互斥,保障同一时刻只有一个节点持有某个逻辑锁 +- 节点注册与发现:基于表dv_server实现节点登记与心跳,结合定时任务进行存活检测与事件通知 + +```mermaid +sequenceDiagram +participant App as "应用/服务" +participant Reg as "MysqlRegistry" +participant Mutex as "MysqlMutex" +participant State as "MysqlServerStateManager" +participant DB as "MySQL" +App->>Reg : 初始化(init) +Reg->>DB : 建立连接 +Reg->>Mutex : 构造分布式锁 +Reg->>State : 构造节点状态管理器 +App->>Reg : acquire(key, timeout) +Reg->>Mutex : acquire(key, timeout) +Mutex->>DB : INSERT dv_registry_lock +DB-->>Mutex : 成功/失败 +Mutex-->>Reg : 返回true/false +App->>Reg : subscribe(key, listener) +Reg->>State : registry(listener) +State->>DB : INSERT/UPDATE dv_server +State->>DB : 定时SELECT dv_server +State-->>App : 通知ADD/REMOVE事件 +App->>Reg : getActiveServerList() +Reg->>State : 获取活跃节点列表 +App->>Reg : release(key) +Reg->>Mutex : release(key) +Mutex->>DB : DELETE dv_registry_lock +Mutex-->>Reg : 返回true/false +App->>Reg : close() +Reg->>Mutex : close() +Reg->>State : close() +``` + +图表来源 +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L1-L107) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) + +## 组件详解 + +### MysqlRegistry:注册中心入口 +- 初始化:从传入的属性中获取数据库连接,构造MysqlMutex与MysqlServerStateManager +- 分布式锁:委托给MysqlMutex的acquire/release +- 订阅/取消订阅:委托给MysqlServerStateManager的registry/unRegistry +- 节点列表:委托给MysqlServerStateManager的getActiveServerList +- 关闭:依次关闭MysqlMutex与MysqlServerStateManager持有的数据库连接 + +章节来源 +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L1-L107) + +### MysqlMutex:基于数据库的分布式锁 +- 锁模型:以“键-持有者-更新时间”三元组存入表dv_registry_lock,唯一索引保证同一时刻仅一个持有者 +- 申请流程:尝试INSERT,若冲突则按固定间隔重试,直至成功或超时 +- 续期机制:单线程定时任务每2秒对持有锁的键执行UPDATE,延长update_time +- 过期清理:删除update_time早于阈值的记录,并同步清理本地持有映射 +- 释放:DELETE对应键,移除本地持有映射 +- 连接管理:检查连接有效性,必要时重建连接 + +```mermaid +flowchart TD +Start(["进入 acquire(key, timeout)"]) --> TryInsert["尝试 INSERT dv_registry_lock"] +TryInsert --> InsertOK{"插入成功?"} +InsertOK --> |是| Hold["返回持有锁成功"] +InsertOK --> |否| Sleep["等待固定间隔"] +Sleep --> Clear["清理过期锁"] +Clear --> Retry["重试计数减一"] +Retry --> More{"还有重试机会?"} +More --> |是| TryInsert +More --> |否| Fail["返回失败"] +subgraph "续期与清理" +Refresh["定时任务: 对持有锁逐个执行 UPDATE"] +ExpireClean["删除过期记录并同步本地映射"] +end +``` + +图表来源 +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218) + +章节来源 +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218) +- [RegistryLock.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/RegistryLock.java#L1-L36) + +### MysqlServerStateManager:节点注册与发现 +- 节点登记:首次注册时INSERT,否则UPDATE,保持update_time最新 +- 心跳:HeartBeater线程每2秒执行一次登记/更新 +- 存活检测:ServerChecker线程每10秒扫描当前所有节点,依据update_time判断离线 +- 事件通知:对比新旧节点集合,对新增/移除分别触发ADD/REMOVE事件 +- 节点列表:返回本地缓存的活跃节点列表 + +```mermaid +sequenceDiagram +participant HB as "HeartBeater(每2s)" +participant SC as "ServerChecker(每10s)" +participant DB as "MySQL" +participant SM as "MysqlServerStateManager" +participant L as "本地缓存(liveServerMap)" +HB->>DB : INSERT/UPDATE dv_server +SC->>DB : SELECT dv_server +DB-->>SC : 当前节点集合 +SC->>SM : refreshServer() +SM->>L : 比较新旧集合 +SM-->>SM : 计算离线/在线节点 +SM-->>SM : 清理离线节点并通知REMOVE +SM-->>L : 更新在线节点并通知ADD +``` + +图表来源 +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) + +章节来源 +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) + +### RegistryLock:锁持有者数据模型 +- 字段:lockKey、lockOwner、updateTime +- 用途:配合MysqlMutex的持有映射,用于续期与过期清理 + +章节来源 +- [RegistryLock.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/RegistryLock.java#L1-L36) + +### ServerInfo:节点信息模型 +- 字段:host、serverPort、createTime、updateTime +- 方法:getAddr()返回“host:port”统一地址格式 + +章节来源 +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java#L1-L49) + +## 依赖关系分析 +- SPI绑定:通过META-INF/plugins/io.datavines.registry.api.Registry将“mysql”别名绑定到MysqlRegistry实现 +- 运行时配置:应用通过application.yaml加载MySQL驱动与连接参数,供MysqlRegistry初始化数据库连接 +- 停止信号:Stopper提供全局停止标志,HeartBeater/ServerChecker在停止状态下不再执行 + +```mermaid +graph LR +SPI["SPI: io.datavines.registry.api.Registry"] --> Impl["实现: MysqlRegistry"] +Impl --> Mutex["MysqlMutex"] +Impl --> State["MysqlServerStateManager"] +State --> Stop["Stopper"] +Impl --> Conn["数据库连接(由属性提供)"] +``` + +图表来源 +- [io.datavines.registry.api.Registry](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/resources/META-INF/plugins/io.datavines.registry.api.Registry#L1-L1) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L1-L107) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L84-L96) +- [Stopper.java](file://datavines-common/src/main/java/io/datavines/common/utils/Stopper.java#L1-L40) + +章节来源 +- [io.datavines.registry.api.Registry](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/resources/META-INF/plugins/io.datavines.registry.api.Registry#L1-L1) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L84-L96) +- [Stopper.java](file://datavines-common/src/main/java/io/datavines/common/utils/Stopper.java#L1-L40) + +## 性能与可靠性特性 +- 锁续期频率:每2秒一次,确保在高并发下减少锁竞争;过期窗口为固定阈值,避免长时间占用 +- 心跳频率:每2秒一次,存活判定窗口为20秒,兼顾实时性与数据库压力 +- 数据库压力控制:锁续期与心跳均为轻量写操作;ServerChecker仅在固定间隔扫描,避免频繁查询 +- 连接健壮性:MysqlMutex/MysqlServerStateManager在执行SQL前检查连接有效性,必要时重建连接 +- 事件幂等:通过唯一索引与去重逻辑,避免重复ADD/REMOVE事件 + +章节来源 +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) + +## 故障排查指南 +- 无法建立数据库连接 + - 检查application.yaml中的MySQL驱动、URL、账号密码是否正确 + - 确认网络连通性与防火墙策略 + - 参考:[application.yaml](file://datavines-server/src/main/resources/application.yaml#L84-L96) +- 锁无法获取/频繁失败 + - 观察是否存在大量竞争;适当增大超时或降低竞争范围 + - 检查数据库慢查询与锁表情况 + - 参考:[MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218) +- 节点未及时下线 + - 检查ServerChecker扫描间隔与心跳间隔设置是否合理 + - 确认Stopper未被置为停止状态 + - 参考:[MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257),[Stopper.java](file://datavines-common/src/main/java/io/datavines/common/utils/Stopper.java#L1-L40) +- 事件风暴或重复通知 + - 检查本地缓存与去重逻辑,确认ADD/REMOVE触发条件 + - 参考:[MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L84-L96) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) +- [Stopper.java](file://datavines-common/src/main/java/io/datavines/common/utils/Stopper.java#L1-L40) + +## 结论 +MySQL注册中心通过“数据库表+定时任务”的方式,实现了可靠的分布式锁与节点注册发现能力。其优势在于实现简单、可移植性强、无需额外中间件;但同时也存在数据库写压力、锁竞争与一致性边界等挑战。建议在生产中结合业务规模评估锁竞争、心跳与检查频率,并做好数据库监控与慢查询治理。 + +## 附录:数据库表结构与配置 + +### 数据库表结构 +- dv_server:集群节点登记表,包含host、port、create_time、update_time +- dv_registry_lock:注册锁表,包含lock_key、lock_owner、create_time、update_time + +章节来源 +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L677-L703) + +### 配置指南 +- 启用MySQL注册中心 + - 在应用配置中切换到MySQL Profile,设置正确的MySQL驱动与连接参数 + - 参考:[application.yaml](file://datavines-server/src/main/resources/application.yaml#L84-L96) +- 注册中心实现绑定 + - 通过SPI将“mysql”别名绑定到MysqlRegistry实现 + - 参考:[io.datavines.registry.api.Registry](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/resources/META-INF/plugins/io.datavines.registry.api.Registry#L1-L1) +- 运行时行为 + - 心跳与检查间隔、锁续期频率、过期窗口等均在代码中硬编码,如需调整请修改相应实现 + - 参考:[MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java#L1-L218),[MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java#L1-L257) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/ZooKeeper\346\263\250\345\206\214\344\270\255\345\277\203.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/ZooKeeper\346\263\250\345\206\214\344\270\255\345\277\203.md" new file mode 100644 index 00000000..ea8c57e3 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/ZooKeeper\346\263\250\345\206\214\344\270\255\345\277\203.md" @@ -0,0 +1,255 @@ +# ZooKeeper注册中心 + + +**本文档引用的文件** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [ZookeeperConnectionStateListener.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZookeeperConnectionStateListener.java) +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ZooKeeperClient.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperClient.java) +- [ZooKeeperConfig.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperConfig.java) +- [ServerInfo.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ServerInfo.java) +- [CommonPropertyUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\CommonPropertyUtils.java) +- [DefaultEnsembleProvider.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\DefaultEnsembleProvider.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障恢复机制](#故障恢复机制) +8. [配置参数说明](#配置参数说明) +9. [性能优化建议](#性能优化建议) +10. [结论](#结论) + +## 简介 +ZooKeeper注册中心是DataVines系统中用于服务发现和协调的核心组件。它基于Apache ZooKeeper实现,提供了高可用、强一致性的分布式协调服务。该注册中心实现了`Registry`接口,支持节点创建、监听器注册、会话管理和故障恢复等关键功能。通过ZooKeeper的临时节点和监听机制,系统能够实时感知服务节点的状态变化,确保集群的稳定运行。 + +## 核心组件 + +ZooKeeper注册中心的核心组件包括`ZooKeeperRegistry`类、`ZookeeperConnectionStateListener`类以及底层的`ZooKeeperClient`。`ZooKeeperRegistry`实现了`Registry`接口,封装了所有与ZooKeeper交互的逻辑。`ZookeeperConnectionStateListener`负责监听ZooKeeper连接状态的变化,当连接丢失或重新连接时通知上层应用。`ZooKeeperClient`则提供了与ZooKeeper集群通信的底层支持,包括会话管理、重试机制和权限控制。 + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java#L43-L240) +- [ZookeeperConnectionStateListener.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZookeeperConnectionStateListener.java#L28-L53) +- [ZooKeeperClient.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperClient.java#L39-L224) + +## 架构概述 + +```mermaid +graph TB +subgraph "应用层" +Registry[Registry接口] +end +subgraph "实现层" +ZooKeeperRegistry[ZooKeeperRegistry] +ZookeeperConnectionStateListener[ZookeeperConnectionStateListener] +end +subgraph "客户端层" +ZooKeeperClient[ZooKeeperClient] +ZooKeeperConfig[ZooKeeperConfig] +DefaultEnsembleProvider[DefaultEnsembleProvider] +end +subgraph "ZooKeeper集群" +ZKNode1[ZooKeeper节点1] +ZKNode2[ZooKeeper节点2] +ZKNode3[ZooKeeper节点3] +end +Registry --> ZooKeeperRegistry +ZooKeeperRegistry --> ZookeeperConnectionStateListener +ZooKeeperRegistry --> ZooKeeperClient +ZooKeeperClient --> ZooKeeperConfig +ZooKeeperClient --> DefaultEnsembleProvider +ZooKeeperClient --> ZKNode1 +ZooKeeperClient --> ZKNode2 +ZooKeeperClient --> ZKNode3 +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [ZookeeperConnectionStateListener.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZookeeperConnectionStateListener.java) +- [ZooKeeperClient.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperClient.java) +- [ZooKeeperConfig.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperConfig.java) +- [DefaultEnsembleProvider.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\DefaultEnsembleProvider.java) + +## 详细组件分析 + +### ZooKeeperRegistry实现分析 + +`ZooKeeperRegistry`类实现了`Registry`接口的所有方法,提供了完整的注册中心功能。在初始化时,它通过`ZooKeeperClient`建立与ZooKeeper集群的连接,并创建表示当前服务器的临时节点。该类使用`TreeCache`来缓存和监听ZooKeeper中的节点变化,当节点被添加、更新或删除时,会通过`SubscribeListener`通知监听器。 + +```mermaid +classDiagram +class Registry { +<> ++init(Properties) ++acquire(String, long) ++release(String) ++subscribe(String, SubscribeListener) ++unSubscribe(String) ++addConnectionListener(ConnectionListener) ++getActiveServerList() ++close() +} +class ZooKeeperRegistry { +-InterProcessMutex mutex +-CuratorFramework client +-Map treeCacheMap +-Properties properties ++init(Properties) ++acquire(String, long) ++release(String) ++subscribe(String, SubscribeListener) ++unSubscribe(String) ++addConnectionListener(ConnectionListener) ++getActiveServerList() ++close() ++exists(String) ++children(String) ++get(String) ++put(String, String, boolean) ++delete(String) +} +class EventAdaptor { ++EventAdaptor(TreeCacheEvent, String) +} +Registry <|.. ZooKeeperRegistry +ZooKeeperRegistry --> EventAdaptor +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java#L43-L240) +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java#L25-L43) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java#L43-L240) + +### ZookeeperConnectionStateListener分析 + +`ZookeeperConnectionStateListener`是ZooKeeper连接状态的监听器,它实现了Curator框架的`ConnectionStateListener`接口。当ZooKeeper连接状态发生变化时,该监听器会收到通知,并将状态转换为`ConnectionStatus`枚举,通过`ConnectionListener`通知上层应用。这种机制使得应用能够及时响应连接丢失和重新连接事件,实现故障恢复。 + +```mermaid +sequenceDiagram +participant Curator as CuratorFramework +participant Listener as ZookeeperConnectionStateListener +participant App as Application +Curator->>Listener : stateChanged(newState) +Listener->>Listener : switch(newState) +alt LOST +Listener->>App : onUpdate(DISCONNECTED) +else RECONNECTED +Listener->>App : onUpdate(RECONNECTED) +end +``` + +**图示来源** +- [ZookeeperConnectionStateListener.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZookeeperConnectionStateListener.java#L28-L53) + +**本节来源** +- [ZookeeperConnectionStateListener.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZookeeperConnectionStateListener.java#L28-L53) + +### 节点创建与管理机制 + +ZooKeeper注册中心使用临时节点(EPHEMERAL)来表示活跃的服务实例。当服务启动时,会创建一个临时节点,节点路径由`SERVERS_KEY`配置项决定,默认为`/datavines/servers`。节点的数据包含服务器的主机名、端口和时间戳信息。由于是临时节点,当服务意外宕机或网络断开时,ZooKeeper会自动删除该节点,从而实现故障检测。 + +```mermaid +flowchart TD +Start([服务启动]) --> CreateNode["创建临时节点
/datavines/servers/host:port"] +CreateNode --> RegisterSuccess["注册成功"] +RegisterSuccess --> Monitor["监控连接状态"] +Monitor --> ConnectionLost{"连接丢失?"} +ConnectionLost --> |是| AutoDelete["ZooKeeper自动删除节点"] +ConnectionLost --> |否| Continue["继续运行"] +AutoDelete --> ServiceDown["服务下线"] +Continue --> Continue +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java#L64-L69) +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java#L164-L176) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java#L64-L69) +- [CommonPropertyUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\CommonPropertyUtils.java#L55-L57) + +## 依赖分析 + +```mermaid +graph LR +ZooKeeperRegistry --> CuratorFramework +ZooKeeperRegistry --> ZooKeeperClient +ZooKeeperClient --> CuratorFramework +ZooKeeperClient --> ZooKeeperConfig +ZooKeeperClient --> DefaultEnsembleProvider +ZooKeeperRegistry --> TreeCache +ZooKeeperRegistry --> InterProcessMutex +``` + +**图示来源** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [ZooKeeperClient.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperClient.java) +- [ZooKeeperConfig.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperConfig.java) +- [DefaultEnsembleProvider.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\DefaultEnsembleProvider.java) + +**本节来源** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java#L26-L31) +- [ZooKeeperClient.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperClient.java#L21-L25) + +## 性能考虑 + +ZooKeeper注册中心的性能主要受ZooKeeper集群性能、网络延迟和客户端配置的影响。通过使用`TreeCache`缓存节点数据,减少了对ZooKeeper的频繁读取操作。同时,合理的重试策略和超时设置可以避免因短暂网络问题导致的服务不可用。在高并发场景下,分布式锁的获取和释放需要特别注意性能影响,建议合理设置锁超时时间。 + +**本节来源** +- [ZooKeeperConfig.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperConfig.java#L23-L31) +- [ZooKeeperClient.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperClient.java#L63-L66) + +## 故障恢复机制 + +ZooKeeper注册中心的故障恢复机制主要依赖于ZooKeeper的会话管理和临时节点特性。当客户端与ZooKeeper集群的连接断开时,`ZookeeperConnectionStateListener`会收到`LOST`状态通知,应用可以据此执行相应的故障处理逻辑。如果连接在会话超时时间内恢复,ZooKeeper会自动重新建立会话,临时节点仍然存在;如果超过会话超时时间,临时节点会被删除,服务需要重新注册。 + +```mermaid +stateDiagram-v2 +[*] --> Connected +Connected --> Disconnected : 连接丢失 +Disconnected --> Connected : 重新连接(会话内) +Disconnected --> Reconnected : 重新连接(新会话) +Disconnected --> NodeDeleted : 会话超时 +NodeDeleted --> Reconnected : 重新注册 +Reconnected --> Connected +``` + +**图示来源** +- [ZookeeperConnectionStateListener.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZookeeperConnectionStateListener.java#L41-L51) +- [ZooKeeperConfig.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperConfig.java#L29-L30) + +**本节来源** +- [ZookeeperConnectionStateListener.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZookeeperConnectionStateListener.java#L41-L51) +- [ZooKeeperConfig.java](file://datavines-common\src\main\java\io\datavines\common\zookeeper\ZooKeeperConfig.java#L29-L30) + +## 配置参数说明 + +ZooKeeper注册中心的主要配置参数如下: + +| 参数名称 | 默认值 | 说明 | +|---------|-------|------| +| registry.zookeeper.server.list | localhost:2181 | ZooKeeper服务器列表 | +| registry.servers.key | /datavines/servers | 服务器信息存储的ZooKeeper路径 | +| registry.job.execution.lock.key | /datavines/job/execution/lock | 作业执行锁的ZooKeeper路径 | +| registry.catalog.metadata.task.lock.key | /datavines/catalog/fetch/lock | 元数据任务锁的ZooKeeper路径 | + +**本节来源** +- [CommonPropertyUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\CommonPropertyUtils.java#L55-L63) + +## 性能优化建议 + +1. **合理设置会话超时时间**:根据网络状况调整`sessionTimeoutMs`,避免因短暂网络抖动导致会话失效。 +2. **使用连接池**:在高并发场景下,考虑使用连接池管理ZooKeeper连接,减少连接创建开销。 +3. **批量操作**:对于多个节点的读写操作,尽量使用批量API减少网络往返次数。 +4. **监控和告警**:建立ZooKeeper集群的监控系统,及时发现和处理性能瓶颈。 +5. **合理分片**:对于大规模集群,考虑使用不同的ZooKeeper路径前缀进行分片,避免单个路径下节点过多。 + +## 结论 + +ZooKeeper注册中心通过`ZooKeeperRegistry`类实现了`Registry`接口,提供了完整的分布式协调功能。它利用ZooKeeper的临时节点、监听器和分布式锁机制,实现了服务发现、状态监控和故障恢复。`ZookeeperConnectionStateListener`确保了连接状态变化能够及时通知上层应用。该实现具有高可用性、强一致性和良好的故障恢复能力,适用于需要可靠服务发现和协调的分布式系统场景。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/datavines-registry\346\250\241\345\235\227.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/datavines-registry\346\250\241\345\235\227.md" new file mode 100644 index 00000000..0929bfe3 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/datavines-registry\346\250\241\345\235\227.md" @@ -0,0 +1,212 @@ +# datavines-registry模块 + + +**本文档引用的文件** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java) +- [Event.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Event.java) +- [SubscribeListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java) +- [ConnectionListener.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java) +- [ConnectionStatus.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionStatus.java) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java) +- [ZookeeperConnectionStateListener.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZookeeperConnectionStateListener.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障转移与高可用机制](#故障转移与高可用机制) +8. [配置参数与性能对比](#配置参数与性能对比) +9. [扩展新注册中心实现指南](#扩展新注册中心实现指南) +10. [结论](#结论) + +## 引言 +datavines-registry模块是DataVines系统中的注册中心核心组件,负责服务发现、分布式锁、集群管理和高可用性保障。该模块提供了两种注册中心实现:基于ZooKeeper的分布式协调服务和基于MySQL的关系型数据库实现。通过统一的SPI接口,系统可以灵活选择不同的注册中心实现,满足不同部署环境的需求。 + +## 核心组件 +datavines-registry模块的核心是`Registry`接口,定义了注册中心的基本功能,包括初始化、获取/释放分布式锁、订阅/取消订阅、获取活跃服务器列表等。`ServerInfo`类用于表示服务器实例信息,包含主机地址、端口、创建和更新时间等属性。`Event`类用于表示注册中心的事件,包括添加、更新和删除操作。`SubscribeListener`接口用于监听注册中心的事件变化,`ConnectionListener`接口用于监听连接状态变化。 + +**核心组件** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L26-L43) +- [ServerInfo.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ServerInfo.java#L30-L48) +- [Event.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Event.java#L19-L106) + +## 架构概述 +datavines-registry模块采用插件化架构,通过SPI机制实现不同注册中心的扩展。核心接口`Registry`定义了注册中心的通用功能,具体的实现类如`ZooKeeperRegistry`和`MysqlRegistry`分别实现了基于ZooKeeper和MySQL的注册中心功能。系统通过配置文件选择具体的注册中心实现,实现了注册中心的可插拔性。 + +```mermaid +graph TB +subgraph "注册中心API" +Registry[Registry接口] +ServerInfo[ServerInfo类] +Event[Event类] +SubscribeListener[SubscribeListener接口] +ConnectionListener[ConnectionListener接口] +end +subgraph "注册中心实现" +ZooKeeperRegistry[ZooKeeperRegistry实现] +MysqlRegistry[MysqlRegistry实现] +end +subgraph "依赖组件" +ZooKeeperClient[ZooKeeper客户端] +HikariCP[HikariCP连接池] +end +Registry --> ZooKeeperRegistry +Registry --> MysqlRegistry +ZooKeeperRegistry --> ZooKeeperClient +MysqlRegistry --> HikariCP +``` + +**图源** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L26-L43) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L43-L176) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L29-L38) + +## 详细组件分析 + +### ZooKeeper注册中心分析 +ZooKeeper注册中心实现基于Apache Curator框架,利用ZooKeeper的临时节点特性实现服务发现和故障检测。当服务实例启动时,会在ZooKeeper中创建临时节点,节点数据包含服务实例的地址信息。当服务实例异常退出时,ZooKeeper会自动删除对应的临时节点,从而实现故障自动发现。 + +```mermaid +classDiagram +class ZooKeeperRegistry { +-InterProcessMutex mutex +-CuratorFramework client +-Map~String, TreeCache~ treeCacheMap +-Properties properties ++init(Properties) void ++acquire(String, long) boolean ++release(String) boolean ++subscribe(String, SubscribeListener) void ++unSubscribe(String) void ++addConnectionListener(ConnectionListener) void ++getActiveServerList() ServerInfo[] ++close() void +} +class ZookeeperConnectionStateListener { +-ConnectionListener listener ++stateChanged(CuratorFramework, ConnectionState) void +} +class MysqlRegistry { +-MysqlMutex mysqlMutex +-MysqlServerStateManager mysqlServerStateManager ++init(Properties) void ++acquire(String, long) boolean ++release(String) boolean ++subscribe(String, SubscribeListener) void ++unSubscribe(String) void ++addConnectionListener(ConnectionListener) void ++getActiveServerList() ServerInfo[] ++close() void +} +class MysqlServerStateManager { +-Connection connection +-Properties properties +-ServerInfo serverInfo +-SubscribeListener subscribeListener ++refreshServer() void ++executeInsert(ServerInfo) void ++executeUpdate(ServerInfo) void ++isExists(ServerInfo) boolean +} +class MysqlMutex { +-Connection connection +-Properties properties +-ServerInfo serverInfo ++acquire(String, long) boolean ++release(String) boolean ++isExists(String, ServerInfo) boolean +} +ZooKeeperRegistry --> ZookeeperConnectionStateListener : "使用" +MysqlRegistry --> MysqlServerStateManager : "使用" +MysqlRegistry --> MysqlMutex : "使用" +``` + +**图源** +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java#L43-L176) +- [ZookeeperConnectionStateListener.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZookeeperConnectionStateListener.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L29-L38) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) +- [MysqlMutex.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java) + +### MySQL注册中心分析 +MySQL注册中心实现基于关系型数据库,通过心跳机制实现服务发现和故障检测。服务实例定期向数据库中的`server_info`表更新自己的状态信息,包括最后更新时间。当服务实例异常退出时,无法继续更新状态,系统通过检查最后更新时间来判断服务实例是否存活。 + +```mermaid +sequenceDiagram +participant 服务实例 +participant MysqlRegistry +participant 数据库 +服务实例->>MysqlRegistry : 启动 +MysqlRegistry->>数据库 : 插入server_info记录 +服务实例->>MysqlRegistry : 定期发送心跳 +MysqlRegistry->>数据库 : 更新last_heartbeat_time +服务实例->>MysqlRegistry : 异常退出 +MysqlRegistry->>数据库 : 无更新 +数据库-->>MysqlRegistry : last_heartbeat_time超时 +MysqlRegistry-->>服务实例 : 标记为不活跃 +``` + +**图源** +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L29-L38) +- [MysqlServerStateManager.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java) + +## 依赖分析 +datavines-registry模块的依赖关系清晰,API模块定义了核心接口,实现模块依赖具体的第三方库。ZooKeeper实现依赖Apache Curator框架和ZooKeeper客户端,MySQL实现依赖HikariCP连接池。通过SPI机制,系统可以在运行时动态选择注册中心实现。 + +```mermaid +graph TD +datavines-registry-api --> datavines-registry-zookeeper +datavines-registry-api --> datavines-registry-mysql +datavines-registry-zookeeper --> zookeeper +datavines-registry-zookeeper --> curator-framework +datavines-registry-zookeeper --> curator-recipes +datavines-registry-mysql --> HikariCP +datavines-registry-mysql --> mysql-connector-java +``` + +**图源** +- [pom.xml](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/pom.xml#L34-L57) +- [pom.xml](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/pom.xml#L33-L36) + +## 性能考虑 +ZooKeeper注册中心在高并发场景下表现优异,得益于ZooKeeper的分布式协调能力。但ZooKeeper集群的维护成本较高,需要专门的运维团队。MySQL注册中心依赖数据库性能,在高并发场景下可能成为性能瓶颈,但部署和维护相对简单。系统设计时需要根据实际业务场景选择合适的注册中心实现。 + +## 故障转移与高可用机制 +ZooKeeper注册中心通过ZooKeeper集群的高可用性保障注册中心本身的高可用。当某个ZooKeeper节点故障时,客户端会自动连接到其他可用节点。MySQL注册中心通过数据库主从复制或集群部署实现高可用。两种实现都提供了服务实例的故障自动发现机制,确保系统能够及时感知服务实例的状态变化。 + +## 配置参数与性能对比 +| 配置项 | ZooKeeper实现 | MySQL实现 | +| --- | --- | --- | +| 连接字符串 | server-lists | jdbc-url | +| 会话超时 | session-timeout-ms | heartbeat-interval-ms | +| 连接超时 | connection-timeout-ms | connection-timeout | +| 重试策略 | retry-policy | retry-attempts | +| 数据持久化 | 临时节点 | 数据库表 | +| 性能 | 高 | 中 | +| 可用性 | 高 | 中 | +| 维护成本 | 高 | 低 | + +## 扩展新注册中心实现指南 +要扩展新的注册中心实现,需要遵循以下步骤: +1. 实现`Registry`接口,提供具体的注册中心功能 +2. 在`META-INF/plugins/io.datavines.registry.api.Registry`文件中添加实现类的映射 +3. 在pom.xml中添加必要的依赖 +4. 通过SPI机制注册实现类 + +最佳实践包括: +- 确保实现类的线程安全性 +- 提供完善的错误处理机制 +- 实现合理的重试策略 +- 提供详细的日志记录 +- 考虑性能和资源消耗 + +## 结论 +datavines-registry模块通过插件化架构提供了灵活的注册中心实现,支持ZooKeeper和MySQL两种主流技术。两种实现各有优劣,ZooKeeper适合对高可用性要求高的场景,MySQL适合对维护成本敏感的场景。系统设计时应根据实际需求选择合适的注册中心实现,并考虑未来的扩展性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/\346\263\250\345\206\214\344\270\255\345\277\203API.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/\346\263\250\345\206\214\344\270\255\345\277\203API.md" new file mode 100644 index 00000000..4a750f08 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-registry\346\250\241\345\235\227/\346\263\250\345\206\214\344\270\255\345\277\203API.md" @@ -0,0 +1,409 @@ +# 注册中心API + + +**本文档引用的文件** +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ConnectionListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\SubscribeListener.java) +- [Event.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Event.java) +- [ConnectionStatus.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionStatus.java) +- [ServerInfo.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ServerInfo.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [RegistryHolder.java](file://datavines-server\src\main\java\io\datavines\server\registry\RegistryHolder.java) +- [SPI.java](file://datavines-spi\src\main\java\io\datavines\spi\SPI.java) + + +## 目录 +1. [简介](#简介) +2. [核心接口设计](#核心接口设计) +3. [服务注册与发现](#服务注册与发现) +4. [监听机制](#监听机制) +5. [分布式锁功能](#分布式锁功能) +6. [连接状态监听](#连接状态监听) +7. [多注册中心实现抽象](#多注册中心实现抽象) +8. [使用示例与最佳实践](#使用示例与最佳实践) +9. [与其他模块集成](#与其他模块集成) +10. [总结](#总结) + +## 简介 +datavines-registry模块为DataVines系统提供了统一的注册中心抽象层,实现了服务注册、服务发现、分布式锁和状态监听等核心功能。该模块通过SPI机制支持多种注册中心实现,包括Zookeeper和MySQL,为分布式环境下的协调服务提供了可靠的基础。 + +**Section sources** +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [SPI.java](file://datavines-spi\src\main\java\io\datavines\spi\SPI.java) + +## 核心接口设计 + +### Registry接口 +Registry接口是注册中心模块的核心,定义了所有注册中心实现必须提供的基本功能。该接口通过@SPI注解标记,表明它是一个可扩展的SPI(Service Provider Interface)接口,允许系统动态加载不同的注册中心实现。 + +```mermaid +classDiagram +class Registry { ++init(Properties properties) void ++acquire(String key, long timeout) boolean ++release(String key) boolean ++subscribe(String key, SubscribeListener listener) void ++unSubscribe(String key) void ++addConnectionListener(ConnectionListener connectionListener) void ++getActiveServerList() ServerInfo[] ++close() void +} +class ConnectionListener { ++onUpdate(ConnectionStatus status) void +} +class SubscribeListener { ++notify(Event event) void +} +class Event { +-key String +-value String +-type Type ++EventBuilder builder() EventBuilder ++key() String ++value() String ++type() Type ++key(String key) Event ++value(String value) Event ++type(Type type) Event +} +class ServerInfo { +-host String +-serverPort Integer +-createTime Timestamp +-updateTime Timestamp ++getAddr() String +} +class ConnectionStatus { +CONNECTED +RECONNECTED +DISCONNECTED +} +class Event~Type~ { +ADD +UPDATE +REMOVE +} +Registry <|.. MysqlRegistry : "实现" +Registry <|.. ZooKeeperRegistry : "实现" +SubscribeListener <.. Event : "通知" +ConnectionListener <.. ConnectionStatus : "状态更新" +``` + +**Diagram sources ** +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ConnectionListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\SubscribeListener.java) +- [Event.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Event.java) +- [ServerInfo.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ServerInfo.java) +- [ConnectionStatus.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionStatus.java) + +**Section sources** +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ConnectionListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionListener.java) +- [SubscribeListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\SubscribeListener.java) +- [Event.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Event.java) +- [ServerInfo.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ServerInfo.java) +- [ConnectionStatus.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionStatus.java) + +## 服务注册与发现 + +### 设计原理 +服务注册与发现功能通过Registry接口的实现来完成。系统中的各个服务实例在启动时会向注册中心注册自己的信息(如主机地址和端口),其他服务可以通过注册中心发现并获取活跃的服务实例列表。 + +### 核心方法 +- `getActiveServerList()`:获取当前活跃的服务实例列表 +- `init(Properties properties)`:初始化注册中心连接 + +### 实现机制 +在Zookeeper实现中,服务信息存储在Zookeeper的特定路径下,使用临时节点(EPHEMERAL)来表示服务实例。当服务正常关闭时,节点会被自动删除;当服务异常终止时,Zookeeper的会话超时机制也会自动清理节点。 + +在MySQL实现中,服务状态信息存储在数据库表中,通过心跳机制来维护服务的活跃状态。 + +```mermaid +sequenceDiagram +participant 服务实例 +participant Registry +participant 注册中心存储 +服务实例->>Registry : init(properties) +Registry->>注册中心存储 : 建立连接 +服务实例->>Registry : put(serverKey, serverInfo, true) +Registry->>注册中心存储 : 创建服务节点(临时) +注册中心存储-->>Registry : 确认 +Registry-->>服务实例 : 完成注册 +服务消费者->>Registry : getActiveServerList() +Registry->>注册中心存储 : 查询活跃服务节点 +注册中心存储-->>Registry : 返回节点列表 +Registry-->>服务消费者 : 返回ServerInfo列表 +``` + +**Diagram sources ** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) + +**Section sources** +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) +- [ServerInfo.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ServerInfo.java) + +## 监听机制 + +### SubscribeListener接口 +SubscribeListener接口用于监听注册中心中特定键值的变化事件。当被监听的键值发生添加、更新或删除操作时,注册中心会通过notify方法通知监听器。 + +### 事件模型 +Event类封装了注册中心的变更事件,包含以下信息: +- key:发生变化的键 +- value:新的值 +- type:事件类型(ADD、UPDATE、REMOVE) + +### 使用场景 +监听机制主要用于服务发现的动态更新。当有新的服务实例注册或现有实例下线时,监听器可以及时收到通知并更新本地的服务列表缓存。 + +```mermaid +flowchart TD +A[注册中心数据变更] --> B{变更类型} +B --> |添加| C[创建Event对象 type=ADD] +B --> |更新| D[创建Event对象 type=UPDATE] +B --> |删除| E[创建Event对象 type=REMOVE] +C --> F[通知所有订阅者] +D --> F +E --> F +F --> G[SubscribeListener.notify(event)] +G --> H[业务逻辑处理] +``` + +**Diagram sources ** +- [SubscribeListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\SubscribeListener.java) +- [Event.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Event.java) +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) + +**Section sources** +- [SubscribeListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\SubscribeListener.java) +- [Event.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Event.java) + +## 分布式锁功能 + +### 设计原理 +分布式锁功能用于在分布式环境中协调多个节点对共享资源的访问,防止并发冲突。Registry接口提供了acquire和release方法来实现锁的获取和释放。 + +### 核心方法 +- `acquire(String key, long timeout)`:尝试获取指定键的锁,带有超时机制 +- `release(String key)`:释放指定键的锁 + +### 实现机制 +在Zookeeper实现中,使用Curator框架的InterProcessMutex来实现分布式锁,基于Zookeeper的临时顺序节点机制。 + +在MySQL实现中,使用MySQL的GET_LOCK和RELEASE_LOCK函数来实现分布式锁。 + +```mermaid +sequenceDiagram +participant 客户端A +participant 客户端B +participant Registry +participant 注册中心存储 +客户端A->>Registry : acquire("job_lock", 30) +Registry->>注册中心存储 : 尝试获取锁 +注册中心存储-->>Registry : 获取成功 +Registry-->>客户端A : 返回true +客户端B->>Registry : acquire("job_lock", 30) +Registry->>注册中心存储 : 尝试获取锁 +注册中心存储-->>Registry : 获取失败(已被占用) +Registry-->>客户端B : 返回false +客户端A->>Registry : release("job_lock") +Registry->>注册中心存储 : 释放锁 +注册中心存储-->>Registry : 确认 +Registry-->>客户端A : 完成 +``` + +**Diagram sources ** +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) + +**Section sources** +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) + +## 连接状态监听 + +### ConnectionListener接口 +ConnectionListener接口用于监听注册中心连接状态的变化。当与注册中心的连接状态发生改变时(如连接、重连、断开),会通过onUpdate方法通知监听器。 + +### 使用场景 +连接状态监听主要用于: +- 监控注册中心的健康状况 +- 在连接断开时执行清理操作 +- 在重新连接后恢复服务注册 +- 实现故障转移和容错机制 + +```mermaid +stateDiagram-v2 +[*] --> 断开 +断开 --> 连接中 : "尝试连接" +连接中 --> 已连接 : "连接成功" +连接中 --> 断开 : "连接失败" +已连接 --> 断开 : "网络故障" +断开 --> 重连中 : "自动重试" +重连中 --> 已连接 : "重连成功" +重连中 --> 断开 : "重试失败" +note right of 已连接 +ConnectionStatus.CONNECTED +end note +note right of 断开 +ConnectionStatus.DISCONNECTED +end note +note right of 重连中 +ConnectionStatus.RECONNECTED +end note +``` + +**Diagram sources ** +- [ConnectionListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionListener.java) +- [ConnectionStatus.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionStatus.java) +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) + +**Section sources** +- [ConnectionListener.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionListener.java) +- [ConnectionStatus.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\ConnectionStatus.java) + +## 多注册中心实现抽象 + +### SPI机制 +datavines-registry模块使用SPI(Service Provider Interface)机制来实现多注册中心的抽象。通过在META-INF/plugins目录下配置实现类,系统可以在运行时动态加载不同的注册中心实现。 + +### 实现类配置 +- Zookeeper实现:`zookeeper=io.datavines.registry.plugin.ZooKeeperRegistry` +- MySQL实现:`mysql=io.datavines.registry.plugin.MysqlRegistry` + +### 抽象层设计 +Registry接口作为抽象层,屏蔽了不同注册中心实现的差异。上层应用只需依赖Registry接口,无需关心具体的实现细节,实现了良好的解耦。 + +```mermaid +graph TB +subgraph "应用层" +A[业务代码] +end +subgraph "抽象层" +B[Registry接口] +end +subgraph "实现层" +C[Zookeeper实现] +D[MySQL实现] +end +subgraph "基础设施" +E[Zookeeper集群] +F[MySQL数据库] +end +A --> B +B --> C +B --> D +C --> E +D --> F +style B fill:#f9f,stroke:#333 +style C fill:#bbf,stroke:#333 +style D fill:#bbf,stroke:#333 +``` + +**Diagram sources ** +- [SPI.java](file://datavines-spi\src\main\java\io\datavines\spi\SPI.java) +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) + +**Section sources** +- [SPI.java](file://datavines-spi\src\main\java\io\datavines\spi\SPI.java) +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [ZooKeeperRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-zookeeper\src\main\java\io\datavines\registry\plugin\ZooKeeperRegistry.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) + +## 使用示例与最佳实践 + +### 基本使用 +```java +// 获取注册中心实例 +Registry registry = PluginLoader.getPluginLoader(Registry.class).load("zookeeper"); + +// 初始化 +Properties properties = new Properties(); +properties.setProperty("registry.zookeeper.server.list", "localhost:2181"); +registry.init(properties); + +// 服务注册 +ServerInfo serverInfo = new ServerInfo("localhost", 8080); +String serverKey = "/datavines/servers"; +registry.put(serverKey, serverInfo.toString(), true); + +// 服务发现 +List activeServers = registry.getActiveServerList(); + +// 分布式锁 +boolean locked = registry.acquire("my_lock", 30); +if (locked) { + try { + // 执行临界区代码 + } finally { + registry.release("my_lock"); + } +} + +// 监听服务变化 +registry.subscribe(serverKey, new SubscribeListener() { + @Override + public void notify(Event event) { + System.out.println("服务变化: " + event); + } +}); +``` + +### 最佳实践 +1. **连接管理**:确保在应用关闭时调用close()方法释放资源 +2. **异常处理**:对注册中心操作进行适当的异常处理和重试机制 +3. **超时设置**:合理设置锁的超时时间,避免死锁 +4. **监听器管理**:及时取消不再需要的订阅,避免内存泄漏 +5. **配置管理**:将注册中心配置外部化,便于环境切换 + +**Section sources** +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) +- [RegistryHolder.java](file://datavines-server\src\main\java\io\datavines\server\registry\RegistryHolder.java) + +## 与其他模块集成 + +### 与datavines-server集成 +在datavines-server模块中,通过RegistryHolder类管理Registry实例的生命周期,并在服务启动时进行注册,在关闭时进行清理。 + +### 集成方式 +1. **依赖注入**:通过Spring的@Component注解将RegistryHolder注入到需要的服务中 +2. **配置驱动**:从配置文件读取注册中心类型和连接参数 +3. **SPI加载**:使用PluginLoader动态加载指定的注册中心实现 + +### 典型应用场景 +- **集群协调**:多个datavines-server实例之间的协调 +- **高可用**:通过服务发现实现负载均衡和故障转移 +- **分布式锁**:确保关键操作的互斥执行 +- **配置同步**:在集群节点间同步配置变更 + +```mermaid +graph LR +A[datavines-server] --> B[RegistryHolder] +B --> C[Registry接口] +C --> D[Zookeeper实现] +C --> E[MySQL实现] +D --> F[Zookeeper集群] +E --> G[MySQL数据库] +style A fill:#f96,stroke:#333 +style B fill:#9f9,stroke:#333 +style C fill:#f9f,stroke:#333 +``` + +**Diagram sources ** +- [RegistryHolder.java](file://datavines-server\src\main\java\io\datavines\server\registry\RegistryHolder.java) +- [Registry.java](file://datavines-registry\datavines-registry-api\src\main\java\io\datavines\registry\api\Registry.java) + +**Section sources** +- [RegistryHolder.java](file://datavines-server\src\main\java\io\datavines\server\registry\RegistryHolder.java) + +## 总结 +datavines-registry模块提供了一个灵活、可扩展的注册中心抽象层,通过统一的API接口支持多种注册中心实现。该模块的核心设计包括服务注册与发现、分布式锁、状态监听等功能,为DataVines系统的分布式协调提供了可靠的基础。通过SPI机制,系统可以轻松切换不同的注册中心实现,满足不同部署环境的需求。在使用时,应遵循最佳实践,合理管理连接和资源,确保系统的稳定性和可靠性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/REST API\346\216\245\345\217\243.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/REST API\346\216\245\345\217\243.md" new file mode 100644 index 00000000..b0d994b2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/REST API\346\216\245\345\217\243.md" @@ -0,0 +1,303 @@ +# REST API接口 + + +**本文档引用的文件** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [UserController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java) +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java) +- [OpenApiController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/OpenApiController.java) +- [UserLogin.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserLogin.java) +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + + +## 目录 +1. [简介](#简介) +2. [API基础信息](#api基础信息) +3. [认证机制](#认证机制) +4. [用户管理API](#用户管理api) +5. [数据源管理API](#数据源管理api) +6. [任务管理API](#任务管理api) +7. [任务执行API](#任务执行api) +8. [工作空间管理API](#工作空间管理api) +9. [开放API](#开放api) +10. [DTO对象设计](#dto对象设计) +11. [错误处理策略](#错误处理策略) +12. [客户端集成指南](#客户端集成指南) + +## 简介 +DataVines服务器模块提供了一套完整的RESTful API接口,用于管理和监控数据质量任务。这些API涵盖了用户认证、数据源管理、任务管理、任务执行监控等核心功能。通过这些API,客户端可以实现对数据质量检查任务的全生命周期管理,包括创建、执行、监控和分析。 + +**本文档引用的文件** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) + +## API基础信息 +DataVines的REST API遵循标准的RESTful设计原则,所有API端点都位于`/api/v1`基础路径下。API使用JSON格式进行请求和响应数据交换,支持标准的HTTP方法(GET、POST、PUT、DELETE)来执行相应的CRUD操作。 + +API版本控制通过URL路径实现,当前版本为v1。所有API响应都遵循统一的响应格式,包含状态码、消息和数据负载。 + +**本文档引用的文件** +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) + +## 认证机制 +DataVines采用基于Token的认证机制,所有需要认证的API请求都必须在HTTP头中包含Authorization令牌。认证流程如下: + +1. 用户通过`/api/v1/login`端点进行身份验证,成功后服务器返回包含Token的响应 +2. 客户端在后续所有请求的Authorization头中携带此Token +3. 服务器通过拦截器验证Token的有效性 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Server as "服务器" +participant TokenManager as "Token管理器" +Client->>Server : POST /api/v1/login +Server->>TokenManager : 验证用户名密码 +TokenManager-->>Server : 生成Token +Server-->>Client : 返回Token +Client->>Server : 带Token的API请求 +Server->>TokenManager : 验证Token +TokenManager-->>Server : Token有效 +Server->>Client : 返回请求数据 +``` + +**图示来源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +**本文档引用的文件** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +## 用户管理API +用户管理API提供了用户登录、注册和密码重置等功能。 + +### 登录API +```mermaid +flowchart TD +Start([登录请求]) --> ValidateCredentials["验证凭据"] +ValidateCredentials --> CredentialsValid{"凭据有效?"} +CredentialsValid --> |否| ReturnError["返回错误"] +CredentialsValid --> |是| GenerateToken["生成Token"] +GenerateToken --> StoreSession["存储会话"] +StoreSession --> ReturnSuccess["返回成功和Token"] +ReturnError --> End([响应]) +ReturnSuccess --> End +``` + +**图示来源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) + +**本文档引用的文件** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [UserLogin.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserLogin.java) + +## 数据源管理API +数据源管理API提供了对各种数据源的完整管理功能,包括创建、测试连接、获取数据库和表结构等。 + +### 数据源管理API端点 +| HTTP方法 | URL路径 | 描述 | 认证要求 | +|---------|-------|------|---------| +| POST | /api/v1/datasource/test | 测试数据源连接 | 是 | +| POST | /api/v1/datasource | 创建数据源 | 是 | +| PUT | /api/v1/datasource | 更新数据源 | 是 | +| DELETE | /api/v1/datasource/{id} | 删除数据源 | 是 | +| GET | /api/v1/datasource/page | 分页获取数据源列表 | 是 | +| GET | /api/v1/datasource/{id}/databases | 获取数据库列表 | 是 | +| GET | /api/v1/datasource/{id}/{database}/tables | 获取表列表 | 是 | +| GET | /api/v1/datasource/{id}/{database}/{table}/columns | 获取列列表 | 是 | +| POST | /api/v1/datasource/execute | 执行SQL脚本 | 是 | +| GET | /api/v1/datasource/type/list | 获取连接器类型列表 | 是 | + +**本文档引用的文件** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java) + +## 任务管理API +任务管理API提供了对数据质量检查任务的完整生命周期管理。 + +### 任务管理API端点 +| HTTP方法 | URL路径 | 描述 | 认证要求 | +|---------|-------|------|---------| +| POST | /api/v1/job | 创建任务 | 是 | +| DELETE | /api/v1/job/{id} | 删除任务 | 是 | +| PUT | /api/v1/job | 更新任务 | 是 | +| GET | /api/v1/job/{id} | 获取任务详情 | 是 | +| GET | /api/v1/job/page | 分页获取任务列表 | 是 | +| POST | /api/v1/job/execute/{id} | 执行任务 | 是 | +| GET | /api/v1/job/execute/config/{id} | 获取任务执行配置 | 是 | +| GET | /api/v1/job/config/{id} | 获取任务配置 | 是 | + +**本文档引用的文件** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) + +## 任务执行API +任务执行API提供了对任务执行过程的监控和管理功能。 + +### 任务执行API端点 +| HTTP方法 | URL路径 | 描述 | 认证要求 | +|---------|-------|------|---------| +| POST | /api/v1/job/execution/submit/data-quality | 提交数据质量任务 | 是 | +| POST | /api/v1/job/execution/submit/data-reconciliation | 提交数据核对任务 | 是 | +| DELETE | /api/v1/job/execution/kill/{executionId} | 终止任务执行 | 是 | +| GET | /api/v1/job/execution/status/{executionId} | 获取任务执行状态 | 是 | +| GET | /api/v1/job/execution/list/{jobId} | 获取任务执行列表 | 是 | +| GET | /api/v1/job/execution/result/{executionId} | 获取任务执行结果 | 是 | +| POST | /api/v1/job/execution/page | 分页获取任务执行列表 | 是 | +| GET | /api/v1/job/execution/errorDataPage | 获取错误数据分页 | 是 | + +**本文档引用的文件** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionPageParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionPageParam.java) + +## 工作空间管理API +工作空间管理API提供了对工作空间的创建、更新、删除和用户管理功能。 + +### 工作空间管理API端点 +| HTTP方法 | URL路径 | 描述 | 认证要求 | +|---------|-------|------|---------| +| POST | /api/v1/workspace | 创建工作空间 | 是 | +| PUT | /api/v1/workspace | 更新工作空间 | 是 | +| DELETE | /api/v1/workspace/{id} | 删除工作空间 | 是 | +| GET | /api/v1/workspace/list | 获取用户的工作空间列表 | 是 | +| POST | /api/v1/workspace/inviteUser | 邀请用户加入工作空间 | 是 | +| DELETE | /api/v1/workspace/removeUser | 从工作空间移除用户 | 是 | +| GET | /api/v1/workspace/userPage | 分页获取工作空间用户列表 | 是 | + +**本文档引用的文件** +- [WorkSpaceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java) +- [WorkSpaceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceCreate.java) + +## 开放API +开放API提供了外部系统集成的接口,允许外部系统提交和监控数据质量任务。 + +### 开放API端点 +| HTTP方法 | URL路径 | 描述 | 认证要求 | +|---------|-------|------|---------| +| POST | /api/v1/openapi/job/execute/{id} | 执行任务 | 是(Token存在检查) | +| POST | /api/v1/openapi/job/execution/kill/{executionId} | 终止任务 | 是(Token存在检查) | +| GET | /api/v1/openapi/job/execution/status/{executionId} | 获取任务状态 | 是(Token存在检查) | +| GET | /api/v1/openapi/job/execution/result/{executionId} | 获取任务结果 | 是(Token存在检查) | + +**本文档引用的文件** +- [OpenApiController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/OpenApiController.java) + +## DTO对象设计 +DataVines采用BO(业务对象)和VO(视图对象)分离的设计模式,确保API请求和响应的数据结构清晰且安全。 + +### BO(业务对象)设计 +BO对象用于API请求参数,包含输入验证注解: + +```mermaid +classDiagram +class DataSourceCreate { ++long workspaceId ++String name ++String type ++String param +} +class JobCreate { ++String name ++long dataSourceId ++String metricType ++Map~String,Object~ metricParameter ++String expectedType ++Map~String,Object~ expectedValueParameter +} +DataSourceCreate --> JobCreate : "包含" +``` + +**图示来源** +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) + +### VO(视图对象)设计 +VO对象用于API响应,只包含需要暴露给客户端的数据: + +```mermaid +classDiagram +class JobExecutionResultVO { ++String checkSubject ++String metricName ++Map~String,Object~ metricParameter ++String checkResult ++String expectedType ++BigDecimal score ++LocalDateTime executionTime +} +class ResultMap { ++int code ++String msg ++Object data ++String token +} +ResultMap --> JobExecutionResultVO : "包含" +``` + +**图示来源** +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java) +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) + +**本文档引用的文件** +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java) +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) + +## 错误处理策略 +DataVines采用统一的错误处理机制,所有API响应都遵循相同的格式,便于客户端处理。 + +### 响应格式 +```json +{ + "code": 200, + "msg": "Success", + "data": {}, + "token": "optional_token" +} +``` + +### 状态码说明 +| 状态码 | 描述 | 说明 | +|-------|------|------| +| 200 | Success | 请求成功 | +| 400 | Bad Request | 请求参数错误 | +| 401 | Unauthorized | 未授权访问 | +| 404 | Not Found | 资源不存在 | +| 500 | Internal Server Error | 服务器内部错误 | + +错误处理由全局异常处理器统一管理,确保所有异常都转换为标准的响应格式。 + +**本文档引用的文件** +- [ResultMap.java](file://datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) + +## 客户端集成指南 +### Swagger文档 +DataVines集成了Swagger,可以通过`/swagger-ui.html`访问API文档,查看所有可用的API端点、请求参数和响应示例。 + +### 认证流程 +1. 调用`/api/v1/login`获取Token +2. 在后续请求的Authorization头中包含Token +3. 处理Token过期情况(状态码401) + +### 最佳实践 +- 使用连接池管理HTTP客户端 +- 实现重试机制处理临时性错误 +- 缓存Token避免频繁登录 +- 使用分页获取大量数据 +- 监控API调用频率避免限流 + +**本文档引用的文件** +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/SLA\344\270\216\345\221\212\350\255\246\347\256\241\347\220\206API.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/SLA\344\270\216\345\221\212\350\255\246\347\256\241\347\220\206API.md" new file mode 100644 index 00000000..93a353d0 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/SLA\344\270\216\345\221\212\350\255\246\347\256\241\347\220\206API.md" @@ -0,0 +1,245 @@ +# SLA与告警管理API + + +**本文档引用的文件** +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java) +- [SlaCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/sla/SlaCreate.java) +- [SlaNotificationCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/sla/SlaNotificationCreate.java) +- [SlaSenderCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/sla/SlaSenderCreate.java) +- [SlaNotificationService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/SlaNotificationService.java) +- [SlaSenderService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/SlaSenderService.java) +- [SlaNotificationVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/SlaNotificationVO.java) +- [SlaSenderVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/SlaSenderVO.java) + + +## 目录 +1. [简介](#简介) +2. [SLA管理接口](#sla管理接口) +3. [SLA告警通知接口](#sla告警通知接口) +4. [通知渠道配置](#通知渠道配置) +5. [SLA规则创建流程示例](#sla规则创建流程示例) +6. [告警状态与通知历史查询](#告警状态与通知历史查询) + +## 简介 +SLA与告警管理API提供了创建、更新和管理SLA规则及告警通知的完整功能。系统通过SlaController和SlaNotificationController两个主要控制器提供RESTful接口,支持将SLA规则与质量检查任务关联,并配置多种通知渠道(如钉钉、邮件等)进行告警通知。 + +**Section sources** +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java#L43-L48) + +## SLA管理接口 + +### SLA规则管理 +SlaController提供了完整的SLA规则管理接口,包括创建、更新、查询和删除操作。 + +#### 创建SLA规则 +通过POST请求创建新的SLA规则,请求体包含SlaCreate对象: + +```json +{ + "name": "string", + "description": "string", + "workspaceId": 0 +} +``` + +**参数说明:** +- **name**: SLA规则名称,不能为空 +- **description**: SLA规则描述 +- **workspaceId**: 工作空间ID,不能为空 + +#### 更新SLA规则 +通过PUT请求更新现有SLA规则,请求体包含SlaUpdate对象(继承自SlaCreate并添加ID字段)。 + +#### 查询SLA规则 +支持多种查询方式: +- 分页查询:`GET /api/v1/sla/page?workspaceId=1&pageNumber=1&pageSize=10` +- 根据SLA ID查询:`GET /api/v1/sla/{slaId}` +- 根据任务ID查询:`GET /api/v1/sla/job/{jobId}` + +#### 删除SLA规则 +通过DELETE请求删除指定ID的SLA规则:`DELETE /api/v1/sla/{id}` + +**Section sources** +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java#L122-L150) +- [SlaCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/sla/SlaCreate.java#L24-L34) + +## SLA告警通知接口 + +### 告警通知管理 +SlaNotificationController(集成在SlaController中)提供了告警通知的管理功能。 + +#### 创建告警通知 +通过POST请求创建告警通知配置: + +```json +{ + "type": "string", + "workspaceId": 0, + "slaId": 0, + "senderId": 0, + "config": "string" +} +``` + +**参数说明:** +- **type**: 通知类型(如"email"、"dingtalk"等) +- **workspaceId**: 工作空间ID +- **slaId**: 关联的SLA规则ID +- **senderId**: 通知发送器ID +- **config**: 通知配置JSON字符串 + +#### 更新告警通知 +通过PUT请求更新告警通知配置,请求体为SlaNotificationUpdate对象(包含ID字段)。 + +#### 查询告警通知 +支持分页查询告警通知配置:`GET /api/v1/sla/notification/page?workspaceId=1&slaId=1&pageNumber=1&pageSize=10` + +#### 删除告警通知 +通过DELETE请求删除指定ID的告警通知:`DELETE /api/v1/sla/notification/{id}` + +**Section sources** +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java#L205-L231) +- [SlaNotificationCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/sla/SlaNotificationCreate.java#L26-L37) + +## 通知渠道配置 + +### 通知发送器管理 +系统支持多种通知渠道,通过SlaSender管理通知发送器配置。 + +#### 创建通知发送器 +通过POST请求创建通知发送器: + +```json +{ + "workspaceId": 0, + "type": "string", + "name": "string", + "config": "string" +} +``` + +**参数说明:** +- **type**: 发送器类型(如"email"、"dingtalk"等) +- **name**: 发送器名称 +- **config**: 发送器配置JSON字符串 + +#### 支持的插件类型 +通过`GET /api/v1/sla/plugin/support`接口获取系统支持的所有通知插件类型。 + +#### 获取配置模板 +通过`GET /api/v1/sla/sender/config/{type}`接口获取指定类型发送器的配置参数模板。 + +**Section sources** +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java#L170-L203) +- [SlaSenderCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/sla/SlaSenderCreate.java#L25-L34) + +## SLA规则创建流程示例 + +### 完整创建流程 +以下是创建SLA规则并与质量检查任务关联的完整流程: + +1. **创建通知发送器** + ```http + POST /api/v1/sla/sender + Content-Type: application/json + + { + "workspaceId": 1, + "type": "email", + "name": "生产环境邮件通知", + "config": "{\"smtpHost\":\"smtp.example.com\",\"smtpPort\":587,\"username\":\"user\",\"password\":\"pass\",\"from\":\"alert@example.com\"}" + } + ``` + +2. **创建SLA规则** + ```http + POST /api/v1/sla + Content-Type: application/json + + { + "name": "核心表数据质量SLA", + "description": "确保核心业务表的数据质量达标", + "workspaceId": 1 + } + ``` + +3. **创建告警通知配置** + ```http + POST /api/v1/sla/notification + Content-Type: application/json + + { + "type": "email", + "workspaceId": 1, + "slaId": 1, + "senderId": 1, + "config": "{\"to\":[\"dba@company.com\",\"dev@company.com\"],\"cc\":[\"manager@company.com\"]}" + } + ``` + +4. **将质量检查任务关联到SLA** + ```http + POST /api/v1/sla/job/createOrUpdate + Content-Type: application/json + + { + "slaId": 1, + "jobIds": [1001, 1002, 1003] + } + ``` + +5. **测试告警配置** + ```http + GET /api/v1/sla/test/1 + ``` + 此接口会发送测试告警,验证通知配置是否正确。 + +**Section sources** +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java#L81-L91) +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java#L93-L101) + +## 告警状态与通知历史查询 + +### 告警状态查询 +系统提供了多种方式查询SLA相关的告警状态: + +#### 查询SLA任务列表 +获取与特定SLA规则关联的所有质量检查任务: + +```http +GET /api/v1/sla/job/page?slaId=1&pageNumber=1&pageSize=10 +``` + +或获取所有关联任务的列表: +```http +GET /api/v1/sla/job/list?slaId=1 +``` + +#### 查询SLA规则列表 +分页查询工作空间内的所有SLA规则: +```http +GET /api/v1/sla/page?workspaceId=1&pageNumber=1&pageSize=10 +``` + +### 通知历史记录 +虽然当前API未直接提供通知历史查询接口,但可以通过以下方式获取相关信息: + +1. **查看告警通知配置历史** + ```http + GET /api/v1/sla/notification/page?workspaceId=1&slaId=1&pageNumber=1&pageSize=10 + ``` + 此接口返回当前有效的告警通知配置,包含更新时间和更新人信息。 + +2. **通过日志系统获取通知历史** + 系统在发送告警时会记录日志,可通过日志系统查询历史通知记录。 + +3. **监控通知发送器状态** + ```http + GET /api/v1/sla/sender/page?workspaceId=1&pageNumber=1&pageSize=10 + ``` + 查看通知发送器的配置和状态。 + +**Section sources** +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java#L66-L78) +- [SlaNotificationVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/SlaNotificationVO.java#L26-L50) +- [SlaSenderVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/SlaSenderVO.java#L24-L45) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\344\273\273\345\212\241\346\211\247\350\241\214\344\270\216\347\233\221\346\216\247API.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\344\273\273\345\212\241\346\211\247\350\241\214\344\270\216\347\233\221\346\216\247API.md" new file mode 100644 index 00000000..76afd4d6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\344\273\273\345\212\241\346\211\247\350\241\214\344\270\216\347\233\221\346\216\247API.md" @@ -0,0 +1,322 @@ +# 任务执行与监控API + + +**本文档引用文件** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionVO.java) +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java) +- [JobExecutionPageParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionPageParam.java) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java) +- [JobExecutionResultService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionResultService.java) +- [JobExecutionResultServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionResultServiceImpl.java) +- [JobExecutionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionInfo.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [JobCheckState.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobCheckState.java) + + +## 目录 +1. [简介](#简介) +2. [核心功能概述](#核心功能概述) +3. [任务执行状态查询接口](#任务执行状态查询接口) +4. [任务执行日志与结果获取](#任务执行日志与结果获取) +5. [历史执行记录分页查询](#历史执行记录分页查询) +6. [质量检查结果与报告](#质量检查结果与报告) +7. [数据模型详解](#数据模型详解) +8. [性能优化建议](#性能优化建议) +9. [错误处理与调试](#错误处理与调试) +10. [总结](#总结) + +## 简介 + +任务执行与监控API是DataVines平台的核心组件之一,用于实时监控数据质量任务的执行状态、获取执行日志、分析检查结果以及查询历史执行记录。该API为用户提供了一套完整的任务生命周期管理能力,支持外部系统集成和自动化监控。 + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L1-L124) + +## 核心功能概述 + +任务执行与监控API提供了以下核心功能: +- 实时查询任务执行状态 +- 获取任务执行结果和质量检查详情 +- 分页查询历史执行记录 +- 支持按状态、时间范围、任务类型等条件过滤 +- 提供聚合统计和趋势分析数据 +- 支持外部数据质量任务提交 + +```mermaid +graph TD +A[客户端] --> B[JobExecutionController] +B --> C[JobExecutionService] +B --> D[JobExecutionResultService] +B --> E[JobExecutionErrorDataService] +C --> F[(数据库)] +D --> F +E --> F +F --> G[执行记录] +F --> H[执行结果] +F --> I[错误数据] +``` + +**Diagram sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L44-L123) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) +- [JobExecutionResultService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionResultService.java) + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L1-L124) + +## 任务执行状态查询接口 + +### 获取任务执行状态 + +通过`GET /api/v1/job/execution/status/{executionId}`端点可以获取指定任务执行实例的当前状态。 + +**接口说明** +- **URL**: `/api/v1/job/execution/status/{executionId}` +- **方法**: GET +- **参数**: executionId(路径参数,执行ID) +- **返回**: 状态描述字符串 + +该接口直接返回任务的当前状态描述,如"执行中"、"成功"、"失败"等。 + +### 终止任务执行 + +通过`DELETE /api/v1/job/execution/kill/{executionId}`端点可以终止正在运行的任务。 + +**接口说明** +- **URL**: `/api/v1/job/execution/kill/{executionId}` +- **方法**: DELETE +- **参数**: executionId(路径参数,执行ID) +- **返回**: 操作结果 + +此操作会强制终止指定的任务执行实例。 + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L67-L77) + +## 任务执行日志与结果获取 + +### 获取任务执行结果 + +系统提供了两个端点来获取任务执行结果: + +1. **获取单个执行结果**:`GET /api/v1/job/execution/result/{executionId}` +2. **获取执行结果列表**:`GET /api/v1/job/execution/list/result/{executionId}` + +**接口说明** +- **URL**: `/api/v1/job/execution/list/result/{executionId}` +- **方法**: GET +- **参数**: executionId(路径参数) +- **返回**: JobExecutionResultVO对象列表 + +该接口返回指定执行实例的详细检查结果,包括指标名称、检查结果、得分等信息。 + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L85-L96) +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java#L26-L45) + +## 历史执行记录分页查询 + +### 分页查询执行历史 + +通过`POST /api/v1/job/execution/page`端点可以分页查询任务执行历史记录。 + +**请求参数(JobExecutionPageParam)** +```json +{ + "datasourceId": 1, + "status": 7, + "searchVal": "test", + "jobId": 100, + "metricType": "table_row_count", + "schemaName": "public", + "tableName": "users", + "columnName": "id", + "startTime": "2023-01-01 00:00:00", + "endTime": "2023-12-31 23:59:59", + "pageNumber": 1, + "pageSize": 10 +} +``` + +**接口说明** +- **URL**: `/api/v1/job/execution/page` +- **方法**: POST +- **参数**: JobExecutionPageParam对象 +- **返回**: 分页结果 + +支持多种过滤条件,包括数据源ID、执行状态、任务ID、指标类型、模式名、表名、列名和时间范围。 + +### 过滤特定状态的任务 + +可以通过设置`status`参数来过滤特定状态的任务执行记录。状态值对应ExecutionStatus枚举: + +| 状态码 | 状态描述 | 中文描述 | +|--------|----------|----------| +| 0 | submitted | 已提交 | +| 1 | running | 执行中 | +| 6 | failure | 失败 | +| 7 | success | 成功 | +| 9 | kill | 强制终止 | + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L98-L102) +- [JobExecutionPageParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionPageParam.java#L23-L57) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java#L28-L57) + +## 质量检查结果与报告 + +### 获取检查结果聚合数据 + +通过`POST /api/v1/job/execution/agg-pie`端点可以获取任务执行的聚合统计信息,通常用于饼图展示。 + +**接口说明** +- **URL**: `/api/v1/job/execution/agg-pie` +- **方法**: POST +- **参数**: JobExecutionDashboardParam对象 +- **返回**: 聚合统计结果 + +### 获取执行趋势数据 + +通过`POST /api/v1/job/execution/trend-bar`端点可以获取任务执行的趋势数据,通常用于柱状图展示。 + +**接口说明** +- **URL**: `/api/v1/job/execution/trend-bar` +- **方法**: POST +- **参数**: JobExecutionDashboardParam对象 +- **返回**: 趋势分析结果 + +这些接口为监控面板提供了数据支持,可以展示任务执行的成功率、失败率等关键指标。 + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java#L112-L122) + +## 数据模型详解 + +### JobExecutionVO 对象结构 + +JobExecutionVO是任务执行视图对象,包含以下字段: + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| id | Long | 执行ID | +| name | String | 任务名称 | +| schemaName | String | 模式名 | +| tableName | String | 表名 | +| columnName | String | 列名 | +| metricType | String | 指标类型 | +| jobType | JobType | 任务类型 | +| status | ExecutionStatus | 执行状态 | +| checkState | JobCheckState | 检查状态 | +| startTime | LocalDateTime | 开始时间 | +| endTime | LocalDateTime | 结束时间 | +| updateTime | LocalDateTime | 更新时间 | + +**状态转换逻辑** +```mermaid +stateDiagram-v2 +[*] --> 已提交 +已提交 --> 执行中 +执行中 --> 成功 +执行中 --> 失败 +执行中 --> 强制终止 +成功 --> [*] +失败 --> [*] +强制终止 --> [*] +``` + +**Section sources** +- [JobExecutionVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionVO.java#L29-L75) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [JobCheckState.java](file://datavines-server/src/main/java/io/datavines/server/enums/JobCheckState.java) + +### JobExecutionResultVO 对象结构 + +JobExecutionResultVO是任务执行结果视图对象,包含以下字段: + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| checkSubject | String | 检查主体 | +| metricName | String | 指标名称 | +| metricParameter | Map | 指标参数 | +| checkResult | String | 检查结果 | +| expectedType | String | 预期类型 | +| resultFormulaFormat | String | 结果公式格式 | +| score | BigDecimal | 得分 | +| executionTime | LocalDateTime | 执行时间 | + +该对象用于传输任务执行的详细检查结果,支持多维度的质量分析。 + +**Section sources** +- [JobExecutionResultVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java#L26-L45) + +## 性能优化建议 + +### 日志流式传输 + +对于长时间运行的任务,建议实现日志流式传输功能,避免一次性加载大量日志数据导致内存溢出。 + +**实现建议** +1. 使用分块传输编码(Chunked Transfer Encoding) +2. 实现日志游标机制,支持断点续传 +3. 添加日志级别过滤功能 +4. 支持日志搜索和高亮 + +### 分页查询优化 + +对于历史记录查询,建议: +- 合理设置分页大小,默认10-20条记录 +- 添加适当的数据库索引 +- 实现缓存机制,减少数据库查询压力 +- 支持异步导出功能,避免长时间HTTP连接 + +### 接口调用最佳实践 + +```mermaid +sequenceDiagram +participant Client +participant Controller +participant Service +participant Database +Client->>Controller : 发送查询请求 +Controller->>Service : 调用服务层 +Service->>Database : 执行数据库查询 +Database-->>Service : 返回查询结果 +Service-->>Controller : 返回处理结果 +Controller-->>Client : 返回JSON响应 +Note right of Client : 建议添加请求缓存
减少重复查询 +``` + +**Diagram sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java) + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java) + +## 错误处理与调试 + +### 常见错误码 + +| 错误码 | 说明 | 解决方案 | +|--------|------|----------| +| 400 | 参数校验失败 | 检查请求参数格式 | +| 404 | 执行ID不存在 | 确认执行ID正确性 | +| 500 | 服务器内部错误 | 查看服务日志 | + +### 调试建议 + +1. 启用详细的日志记录 +2. 使用统一的异常处理机制 +3. 添加请求ID用于追踪 +4. 实现健康检查端点 + +**Section sources** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobExecutionServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java) + +## 总结 + +任务执行与监控API为DataVines平台提供了完整的任务生命周期管理能力。通过这套API,用户可以实时监控任务状态、获取执行结果、查询历史记录并进行质量分析。建议在实际使用中结合性能优化建议,确保系统的稳定性和响应速度。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\344\273\273\345\212\241\347\256\241\347\220\206API.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\344\273\273\345\212\241\347\256\241\347\220\206API.md" new file mode 100644 index 00000000..b068fa3a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\344\273\273\345\212\241\347\256\241\347\220\206API.md" @@ -0,0 +1,310 @@ +# 任务管理API + + +**本文档引用的文件** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) +- [JobUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobUpdate.java) +- [JobVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobVO.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [任务管理API端点](#任务管理api端点) +4. [任务执行API端点](#任务执行api端点) +5. [任务质量报告API端点](#任务质量报告api端点) +6. [BO对象字段说明](#bo对象字段说明) +7. [VO对象数据结构](#vo对象数据结构) +8. [数据质量检查任务JSON示例](#数据质量检查任务json示例) +9. [任务状态生命周期](#任务状态生命周期) +10. [分页参数说明](#分页参数说明) +11. [错误响应码及解决方法](#错误响应码及解决方法) +12. [API调用流程](#api调用流程) + +## 简介 +任务管理API是DataVines平台的核心功能之一,提供对数据质量检查、数据校验等任务的全生命周期管理。该API支持任务的创建、更新、删除、查询和执行操作,为数据质量保障提供完整的RESTful接口支持。 + +## 核心组件 + +**本文档引用的文件** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) + +## 任务管理API端点 + +### 创建任务 +- **HTTP方法**: POST +- **URL路径**: `/api/v1/job/create` +- **请求体**: JobCreate对象 +- **响应格式**: 创建成功的任务ID + +### 更新任务 +- **HTTP方法**: PUT +- **URL路径**: `/api/v1/job/update` +- **请求体**: JobUpdate对象 +- **响应格式**: 更新成功的任务信息 + +### 删除任务 +- **HTTP方法**: DELETE +- **URL路径**: `/api/v1/job/delete/{id}` +- **路径参数**: id - 任务ID +- **响应格式**: 删除操作结果 + +### 查询任务 +- **HTTP方法**: GET +- **URL路径**: `/api/v1/job/list` +- **查询参数**: + - pageNumber - 页码 + - pageSize - 每页大小 + - searchVal - 搜索关键字 +- **响应格式**: 分页的任务列表 + +**本文档引用的文件** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) + +## 任务执行API端点 + +### 提交数据质量任务 +- **HTTP方法**: POST +- **URL路径**: `/api/v1/job/execution/submit/data-quality` +- **请求体**: SubmitJob对象 +- **响应格式**: 提交结果和执行ID + +### 提交数据校验任务 +- **HTTP方法**: POST +- **URL路径**: `/api/v1/job/execution/submit/data-reconciliation` +- **请求体**: SubmitJob对象 +- **响应格式**: 提交结果和执行ID + +### 终止任务 +- **HTTP方法**: DELETE +- **URL路径**: `/api/v1/job/execution/kill/{executionId}` +- **路径参数**: executionId - 执行ID +- **响应格式**: 终止操作结果 + +### 获取任务状态 +- **HTTP方法**: GET +- **URL路径**: `/api/v1/job/execution/status/{executionId}` +- **路径参数**: executionId - 执行ID +- **响应格式**: 任务当前状态描述 + +### 按任务ID获取执行列表 +- **HTTP方法**: GET +- **URL路径**: `/api/v1/job/execution/list/{jobId}` +- **路径参数**: jobId - 任务ID +- **响应格式**: 该任务的所有执行记录列表 + +**本文档引用的文件** +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) + +## 任务质量报告API端点 + +### 获取质量报告分页数据 +- **HTTP方法**: POST +- **URL路径**: `/api/v1/job/quality-report/page` +- **请求体**: JobQualityReportDashboardParam对象 +- **响应格式**: 分页的质量报告数据 + +### 获取质量评分 +- **HTTP方法**: POST +- **URL路径**: `/api/v1/job/quality-report/score` +- **请求体**: JobQualityReportDashboardParam对象 +- **响应格式**: 质量评分和等级 + +### 获取质量评分趋势 +- **HTTP方法**: POST +- **URL路径**: `/api/v1/job/quality-report/score/trend` +- **请求体**: JobQualityReportDashboardParam对象 +- **响应格式**: 质量评分趋势数据 + +**本文档引用的文件** +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) + +## BO对象字段说明 + +### JobCreate对象 +- **name**: 任务名称,不能为空 +- **schemaName**: 模式名称 +- **tableName**: 表名称 +- **columnName**: 列名称 +- **type**: 任务类型,从JobType枚举中选择 +- **updater**: 更新者 + +### JobUpdate对象 +- 继承JobCreate的所有字段 +- **id**: 任务ID,不能为空,用于标识要更新的任务 + +### JobExecutionPageParam对象 +- **datasourceId**: 数据源ID +- **status**: 执行状态 +- **searchVal**: 搜索关键字 +- **jobId**: 任务ID +- **metricType**: 指标类型 +- **schemaName**: 模式名称 +- **tableName**: 表名称 +- **columnName**: 列名称 +- **startTime**: 开始时间 +- **endTime**: 结束时间 +- **pageNumber**: 页码 +- **pageSize**: 每页大小 + +**本文档引用的文件** +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) +- [JobUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobUpdate.java) +- [JobExecutionPageParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionPageParam.java) + +## VO对象数据结构 + +### JobVO对象 +- **id**: 任务ID +- **name**: 任务名称 +- **schemaName**: 模式名称 +- **tableName**: 表名称 +- **columnName**: 列名称 +- **type**: 任务类型 +- **updater**: 更新者 +- **slaList**: SLA列表 + +### JobExecutionVO对象 +- **id**: 执行ID +- **name**: 任务名称 +- **schemaName**: 模式名称 +- **status**: 执行状态 +- **startTime**: 开始时间 +- **endTime**: 结束时间 +- **applicationId**: 应用ID + +### JobQualityReportVO对象 +- **id**: 报告ID +- **datasourceId**: 数据源ID +- **schemaName**: 模式名称 +- **tableName**: 表名称 +- **score**: 质量评分 +- **reportDate**: 报告日期 +- **qualityLevel**: 质量等级 + +**本文档引用的文件** +- [JobVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobVO.java) +- [JobExecutionVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionVO.java) + +## 数据质量检查任务JSON示例 + +```json +{ + "job": { + "name": "用户表数据质量检查", + "schemaName": "public", + "tableName": "users", + "columnName": "email", + "type": "DATA_QUALITY", + "updater": "admin" + }, + "jobParameter": { + "metricType": "COLUMN_NOT_NULL", + "expectedValue": { + "type": "FIX", + "value": "true" + }, + "source": { + "datasourceId": 1, + "database": "production_db", + "table": "users" + } + }, + "schedule": { + "type": "CRON", + "expression": "0 0 2 * * ?" + } +} +``` + +**本文档引用的文件** +- [JobCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobCreate.java) + +## 任务状态生命周期 + +任务执行状态遵循以下生命周期: + +```mermaid +stateDiagram-v2 +[*] --> SUBMITTED_SUCCESS +SUBMITTED_SUCCESS --> RUNNING_EXECUTION +RUNNING_EXECUTION --> SUCCESS +RUNNING_EXECUTION --> FAILURE +RUNNING_EXECUTION --> NEED_FAULT_TOLERANCE +RUNNING_EXECUTION --> KILL +RUNNING_EXECUTION --> PAUSE +PAUSE --> RUNNING_EXECUTION +KILL --> [*] +SUCCESS --> [*] +FAILURE --> [*] +NEED_FAULT_TOLERANCE --> [*] +``` + +**本文档引用的文件** +- [ExecutionStatus.java](file://datavines-common/src/main/java/io/datavines/common/enums/ExecutionStatus.java) + +## 分页参数说明 + +所有分页查询接口均支持以下参数: + +| 参数名 | 类型 | 必需 | 描述 | +|--------|------|------|------| +| pageNumber | Integer | 是 | 当前页码,从1开始 | +| pageSize | Integer | 是 | 每页记录数,建议不超过100 | +| searchVal | String | 否 | 搜索关键字,用于模糊匹配 | +| schemaSearch | String | 否 | 模式名称搜索 | +| tableSearch | String | 否 | 表名称搜索 | +| columnSearch | String | 否 | 列名称搜索 | + +这些参数通过请求体传递,用于控制查询结果的分页和过滤。 + +**本文档引用的文件** +- [JobExecutionPageParam.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/job/JobExecutionPageParam.java) + +## 错误响应码及解决方法 + +| 错误码 | 错误类型 | 描述 | 解决方法 | +|--------|----------|------|----------| +| 400 | Bad Request | 请求参数无效 | 检查请求体中的必填字段是否完整,数据类型是否正确 | +| 404 | Not Found | 资源未找到 | 确认请求的资源ID是否存在,URL路径是否正确 | +| 500 | Internal Server Error | 服务器内部错误 | 检查服务器日志,联系系统管理员 | +| 401 | Unauthorized | 未授权访问 | 确保请求包含有效的认证令牌 | +| 403 | Forbidden | 禁止访问 | 确认当前用户有权限执行该操作 | + +**本文档引用的文件** +- [Status.java](file://datavines-core/src/main/java/io/datavines/core/enums/Status.java) + +## API调用流程 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant JobController as "JobController" +participant JobExecutionController as "JobExecutionController" +participant JobQualityReportController as "JobQualityReportController" +Client->>JobController : POST /api/v1/job/create +JobController-->>Client : 返回任务ID +Client->>JobExecutionController : POST /api/v1/job/execution/submit/data-quality +JobExecutionController-->>Client : 返回执行ID +Client->>JobExecutionController : GET /api/v1/job/execution/status/{executionId} +JobExecutionController-->>Client : 返回执行状态 +loop 每5秒轮询一次 +Client->>JobExecutionController : GET /api/v1/job/execution/status/{executionId} +JobExecutionController-->>Client : 返回执行状态 +end +Client->>JobQualityReportController : POST /api/v1/job/quality-report/page +JobQualityReportController-->>Client : 返回质量报告数据 +Client->>JobQualityReportController : POST /api/v1/job/quality-report/score +JobQualityReportController-->>Client : 返回质量评分 +``` + +**本文档引用的文件** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [JobExecutionController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java) +- [JobQualityReportController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobQualityReportController.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\345\267\245\344\275\234\347\251\272\351\227\264\344\270\216\347\247\237\346\210\267API.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\345\267\245\344\275\234\347\251\272\351\227\264\344\270\216\347\247\237\346\210\267API.md" new file mode 100644 index 00000000..4ff8309c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\345\267\245\344\275\234\347\251\272\351\227\264\344\270\216\347\247\237\346\210\267API.md" @@ -0,0 +1,260 @@ +# 工作空间与租户API + + +**本文档引用的文件** +- [WorkSpaceController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\WorkSpaceController.java) +- [TenantController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\TenantController.java) +- [WorkSpaceService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\WorkSpaceService.java) +- [TenantService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\TenantService.java) +- [WorkSpaceCreate.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\workspace\WorkSpaceCreate.java) +- [WorkSpaceUpdate.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\workspace\WorkSpaceUpdate.java) +- [InviteUserIntoWorkspace.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\workspace\InviteUserIntoWorkspace.java) +- [RemoveUserOutWorkspace.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\workspace\RemoveUserOutWorkspace.java) +- [TenantCreate.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\tenant\TenantCreate.java) +- [TenantUpdate.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\tenant\TenantUpdate.java) +- [WorkSpace.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\WorkSpace.java) +- [Tenant.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\Tenant.java) +- [WorkSpaceVO.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\vo\WorkSpaceVO.java) + + +## 目录 +1. [简介](#简介) +2. [工作空间管理API](#工作空间管理api) +3. [租户管理API](#租户管理api) +4. [权限与资源访问控制](#权限与资源访问控制) +5. [API调用示例](#api调用示例) +6. [最佳实践](#最佳实践) + +## 简介 +本文档详细描述了DataVines平台中工作空间(Workspace)与租户(Tenant)管理的API接口。系统采用多租户架构,通过工作空间实现用户分组和资源隔离,每个工作空间下可创建多个租户用于资源配置和管理。API提供了创建、更新、删除工作空间,邀请/移除用户,以及管理租户配额等核心功能。 + +**本文档不包含具体代码内容,所有实现细节均通过引用源文件进行追踪。** + +## 工作空间管理API + +工作空间是多租户环境下的顶级组织单元,用于隔离不同团队或项目的资源。WorkSpaceController提供了完整的工作空间生命周期管理接口。 + +### 创建工作空间 +通过POST请求创建新的工作空间,请求体需包含工作空间名称。 + +**接口信息** +- **方法**: POST +- **路径**: `/api/v1/workspace` +- **请求体**: `WorkSpaceCreate` 对象 +- **成功响应**: 新创建的工作空间ID + +### 更新工作空间 +通过PUT请求更新现有工作空间的信息。 + +**接口信息** +- **方法**: PUT +- **路径**: `/api/v1/workspace` +- **请求体**: `WorkSpaceUpdate` 对象(包含ID和新名称) +- **成功响应**: 布尔值,表示更新是否成功 + +### 删除工作空间 +通过DELETE请求删除指定ID的工作空间。 + +**接口信息** +- **方法**: DELETE +- **路径**: `/api/v1/workspace/{id}` +- **路径参数**: `id` - 工作空间ID +- **成功响应**: 布尔值,表示删除是否成功 + +### 查询工作空间列表 +获取当前用户所属的所有工作空间列表。 + +**接口信息** +- **方法**: GET +- **路径**: `/api/v1/workspace/list` +- **成功响应**: `WorkSpaceVO` 对象列表 + +### 用户管理 +提供邀请用户加入和移除用户出工作空间的功能。 + +#### 邀请用户 +邀请新用户加入指定工作空间。 + +**接口信息** +- **方法**: POST +- **路径**: `/api/v1/workspace/inviteUser` +- **请求体**: `InviteUserIntoWorkspace` 对象(包含用户名、邮箱和工作空间ID) +- **成功响应**: 新创建的用户关系ID + +#### 移除用户 +将用户从工作空间中移除。 + +**接口信息** +- **方法**: DELETE +- **路径**: `/api/v1/workspace/removeUser` +- **请求体**: `RemoveUserOutWorkspace` 对象(包含用户ID和工作空间ID) +- **成功响应**: 布尔值,表示移除是否成功 + +#### 查询工作空间用户 +分页查询指定工作空间中的用户列表。 + +**接口信息** +- **方法**: GET +- **路径**: `/api/v1/workspace/userPage` +- **查询参数**: `workspaceId`, `pageNumber`, `pageSize` +- **成功响应**: 分页的用户信息列表 + +**接口来源** +- [WorkSpaceController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\WorkSpaceController.java#L44-L88) +- [WorkSpaceService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\WorkSpaceService.java#L32-L49) +- [WorkSpaceCreate.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\workspace\WorkSpaceCreate.java#L24-L31) +- [WorkSpaceUpdate.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\workspace\WorkSpaceUpdate.java#L24-L32) +- [InviteUserIntoWorkspace.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\workspace\InviteUserIntoWorkspace.java#L24-L37) +- [RemoveUserOutWorkspace.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\workspace\RemoveUserOutWorkspace.java#L23-L33) +- [WorkSpaceVO.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\vo\WorkSpaceVO.java#L25-L45) + +## 租户管理API + +租户是工作空间下的资源管理单元,用于实现资源配额控制和环境隔离。TenantController提供了租户的CRUD操作和查询接口。 + +### 创建租户 +在指定工作空间下创建新的租户。 + +**接口信息** +- **方法**: POST +- **路径**: `/api/v1/tenant` +- **请求体**: `TenantCreate` 对象(包含工作空间ID和租户名称) +- **成功响应**: 新创建的租户ID + +### 更新租户 +更新现有租户的信息。 + +**接口信息** +- **方法**: PUT +- **路径**: `/api/v1/tenant` +- **请求体**: `TenantUpdate` 对象 +- **成功响应**: 布尔值,表示更新是否成功 + +### 删除租户 +删除指定ID的租户。 + +**接口信息** +- **方法**: DELETE +- **路径**: `/api/v1/tenant/{id}` +- **路径参数**: `id` - 租户ID +- **成功响应**: 布尔值,表示删除是否成功 + +### 查询租户列表 +获取指定工作空间下的所有租户列表。 + +**接口信息** +- **方法**: GET +- **路径**: `/api/v1/tenant/list/{workspaceId}` +- **路径参数**: `workspaceId` - 工作空间ID +- **成功响应**: `Tenant` 对象列表 + +### 查询租户选项 +获取指定工作空间下租户的选项列表,用于前端下拉框展示。 + +**接口信息** +- **方法**: GET +- **路径**: `/api/v1/tenant/listOptions/{workspaceId}` +- **路径参数**: `workspaceId` - 工作空间ID +- **成功响应**: `Item` 对象列表(包含租户名称和ID) + +**接口来源** +- [TenantController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\TenantController.java#L47-L85) +- [TenantService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\TenantService.java#L28-L39) +- [TenantCreate.java](file://datavines-server\src\main\java\io\datavines\server\api\dto\bo\tenant\TenantCreate.java#L24-L33) + +## 权限与资源访问控制 + +系统实现了基于工作空间的多层权限控制机制,确保资源的安全访问。 + +### 认证与授权 +所有API请求都需要有效的认证令牌。系统通过`@RefreshToken`注解实现令牌刷新机制,确保长时间会话的安全性。`AuthenticationInterceptor`拦截器负责验证用户身份和权限。 + +### 跨工作空间访问限制 +系统严格限制跨工作空间的资源访问: +- 用户只能访问其所属工作空间的资源 +- 租户与工作空间强关联,无法跨空间访问 +- 数据源、作业等资源均绑定到特定工作空间 +- API调用时需确保操作的资源属于用户有权访问的工作空间 + +### 权限分配 +权限通过工作空间成员关系进行分配: +- 工作空间创建者默认拥有管理员权限 +- 邀请加入的用户根据角色获得相应权限 +- 租户级别的资源配置影响该租户下所有作业的资源使用 + +**权限来源** +- [WorkSpaceController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\WorkSpaceController.java#L38) +- [TenantController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\TenantController.java#L41) +- [AuthenticationInterceptor.java](file://datavines-server\src\main\java\io\datavines\server\inteceptor\AuthenticationInterceptor.java) + +## API调用示例 + +### 创建工作空间 +```http +POST /api/v1/workspace HTTP/1.1 +Content-Type: application/json +Authorization: Bearer + +{ + "name": "数据分析团队" +} +``` + +### 邀请用户 +```http +POST /api/v1/workspace/inviteUser HTTP/1.1 +Content-Type: application/json +Authorization: Bearer + +{ + "username": "zhangsan", + "email": "zhangsan@company.com", + "workspaceId": 1 +} +``` + +### 创建租户 +```http +POST /api/v1/tenant HTTP/1.1 +Content-Type: application/json +Authorization: Bearer + +{ + "workspaceId": 1, + "tenant": "production" +} +``` + +### 查询工作空间用户 +```http +GET /api/v1/workspace/userPage?workspaceId=1&pageNumber=1&pageSize=10 HTTP/1.1 +Authorization: Bearer +``` + +## 最佳实践 + +### 工作空间设计 +- 为不同团队或项目创建独立的工作空间 +- 使用有意义的名称便于识别和管理 +- 定期审查工作空间成员,确保权限最小化 + +### 租户管理 +- 在每个工作空间内创建多个租户用于环境隔离(如dev、test、prod) +- 通过租户实现资源配额控制 +- 遵循命名规范,便于识别租户用途 + +### 安全建议 +- 严格控制工作空间创建权限 +- 定期审计用户邀请和移除操作 +- 使用强密码策略和多因素认证 +- 限制敏感操作的权限范围 + +### 性能考虑 +- 批量操作时使用分页查询避免性能问题 +- 合理设置租户资源配额防止资源滥用 +- 定期清理不再使用的租户和工作空间 + +**最佳实践来源** +- [WorkSpaceController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\WorkSpaceController.java) +- [TenantController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\TenantController.java) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\346\225\260\346\215\256\346\272\220\347\256\241\347\220\206API.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\346\225\260\346\215\256\346\272\220\347\256\241\347\220\206API.md" new file mode 100644 index 00000000..6573193d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\346\225\260\346\215\256\346\272\220\347\256\241\347\220\206API.md" @@ -0,0 +1,207 @@ +# 数据源管理API + + +**本文档中引用的文件** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java) +- [DataSourceUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceUpdate.java) +- [TestConnectionRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java) +- [ConnectorRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorRequestParam.java) +- [ExecuteRequest.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/ExecuteRequest.java) +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java) +- [GetDatabasesRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/GetDatabasesRequestParam.java) +- [GetTablesRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/GetTablesRequestParam.java) +- [GetColumnsRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/GetColumnsRequestParam.java) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) + + +## 目录 +1. [简介](#简介) +2. [核心接口说明](#核心接口说明) +3. [数据源创建请求体](#数据源创建请求体) +4. [数据库/表/列信息获取](#数据库表列信息获取) +5. [测试连接接口](#测试连接接口) +6. [敏感信息加密传输](#敏感信息加密传输) +7. [权限校验机制](#权限校验机制) + +## 简介 +数据源管理API提供了对各类数据源的全生命周期管理功能,包括数据源的增删改查、连接测试以及数据库元数据获取等操作。该API通过统一的接口设计支持多种数据库类型,并确保敏感信息的安全传输与存储。 + +**Section sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L48-L167) + +## 核心接口说明 +数据源管理API提供了以下核心接口: + +- **创建数据源**: `POST /api/v1/datasource` +- **更新数据源**: `PUT /api/v1/datasource` +- **删除数据源**: `DELETE /api/v1/datasource/{id}` +- **获取数据源分页列表**: `GET /api/v1/datasource/page` +- **测试连接**: `POST /api/v1/datasource/test` +- **获取数据库列表**: `GET /api/v1/datasource/{id}/databases` +- **获取表列表**: `GET /api/v1/datasource/{id}/{database}/tables` +- **获取列信息**: `GET /api/v1/datasource/{id}/{database}/{table}/columns` +- **执行脚本**: `POST /api/v1/datasource/execute` +- **获取配置JSON**: `GET /api/v1/datasource/config/{type}` +- **获取连接器类型列表**: `GET /api/v1/datasource/type/list` + +这些接口由`DataSourceController`统一提供,通过RESTful风格设计,便于集成和使用。 + +```mermaid +flowchart TD +A[客户端] --> B[DataSourceController] +B --> C[DataSourceService] +C --> D[DataSourceMapper] +C --> E[ConnectorFactory] +E --> F[具体连接器实现] +``` + +**Diagram sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L48-L167) +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java#L32-L59) + +**Section sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L48-L167) +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java#L32-L59) + +## 数据源创建请求体 +`DataSourceCreate`请求体用于创建新的数据源,包含以下参数: + +- **workspaceId**: 工作空间ID,不能为空 +- **name**: 数据源名称,不能为空 +- **type**: 数据源类型(如mysql、postgresql等),不能为空 +- **param**: 连接参数,以JSON字符串形式传递,不能为空 + +其中`param`字段包含具体的连接信息,如JDBC URL、用户名、密码等,这些敏感信息在传输和存储过程中都会进行加密处理。 + +```mermaid +classDiagram +class DataSourceCreate { ++long workspaceId ++String name ++String type ++String param +} +``` + +**Diagram sources** +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java#L26-L39) + +**Section sources** +- [DataSourceCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java#L26-L39) + +## 数据库表列信息获取 +系统提供了获取指定数据源的数据库、表和列信息的接口: + +### 获取数据库列表 +通过`GET /api/v1/datasource/{id}/databases`接口获取指定数据源的所有数据库列表。系统会根据数据源ID查询其配置信息,并通过对应的连接器获取数据库列表。 + +### 获取表列表 +通过`GET /api/v1/datasource/{id}/{database}/tables`接口获取指定数据库中的所有表。需要提供数据源ID和数据库名称。 + +### 获取列信息 +通过`GET /api/v1/datasource/{id}/{database}/{table}/columns`接口获取指定表的所有列信息。需要提供数据源ID、数据库名称和表名。 + +这些操作的实现依赖于`ConnectorFactory`插件机制,不同类型的数据库通过各自的连接器实现来获取元数据。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "DataSourceController" +participant Service as "DataSourceService" +participant Connector as "ConnectorFactory" +Client->>Controller : GET /datasource/{id}/databases +Controller->>Service : getDatabaseList(id) +Service->>Service : getDataSourceById(id) +Service->>Connector : getDatabases(param) +Connector-->>Service : 返回数据库列表 +Service-->>Controller : 返回结果 +Controller-->>Client : 返回数据库列表 +``` + +**Diagram sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L89-L99) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L269-L286) + +**Section sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L89-L131) +- [GetDatabasesRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/GetDatabasesRequestParam.java#L17-L26) +- [GetTablesRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/GetTablesRequestParam.java#L17-L27) +- [GetColumnsRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/GetColumnsRequestParam.java#L17-L30) + +## 测试连接接口 +测试连接接口用于验证数据源配置的正确性: + +- **接口地址**: `POST /api/v1/datasource/test` +- **请求体**: `TestConnectionRequestParam` +- **返回值**: 布尔值,true表示连接成功,false表示连接失败 + +该接口接收包含数据源类型和连接参数的请求体,通过`PluginLoader`加载对应的`ConnectorFactory`,然后调用连接器的测试连接方法。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "DataSourceController" +participant Service as "DataSourceService" +participant Factory as "ConnectorFactory" +Client->>Controller : POST /datasource/test +Controller->>Service : testConnect(param) +Service->>Factory : getOrCreatePlugin(type) +Factory->>Factory : getConnector() +Factory->>Factory : testConnect(param) +Factory-->>Service : 返回测试结果 +Service-->>Controller : 返回结果 +Controller-->>Client : 返回true/false +``` + +**Diagram sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L56-L60) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L76-L80) + +**Section sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L56-L60) +- [TestConnectionRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java#L17-L26) +- [ConnectorRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/ConnectorRequestParam.java#L17-L28) + +## 敏感信息加密传输 +系统对数据源的敏感信息(如密码)采用AES加密算法进行加密传输和存储: + +- **加密算法**: AES/CBC/PKCS5Padding +- **密钥**: 从配置文件中读取的AES密钥 +- **IV参数**: 0123456789ABCEDF + +在创建或更新数据源时,系统会自动对`param`字段进行AES加密,然后存储到数据库中。在读取数据源信息时,再进行解密操作。同时,在返回给前端的响应中,密码字段会被替换为NULL,以防止敏感信息泄露。 + +```mermaid +flowchart TD +A[原始参数] --> B{创建/更新} +B --> C[使用AES加密] +C --> D[存储到数据库] +D --> E{查询} +E --> F[从数据库读取] +F --> G[使用AES解密] +G --> H[过滤密码字段] +H --> I[返回给前端] +``` + +**Diagram sources** +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L113-L116) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L25-L84) + +**Section sources** +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L113-L116) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L25-L84) + +## 权限校验机制 +系统通过以下机制实现权限校验: + +1. **Token校验**: 使用`@RefreshToken`注解和`AuthenticationInterceptor`拦截器对每个API请求进行Token校验 +2. **工作空间隔离**: 数据源与工作空间关联,用户只能访问所属工作空间的数据源 +3. **操作权限控制**: 通过`ContextHolder.getUserId()`获取当前用户ID,确保只有创建者或管理员才能进行修改和删除操作 + +这些机制确保了数据源管理的安全性和数据隔离性。 + +**Section sources** +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L47) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L123-L124) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\350\256\244\350\257\201\344\270\216\347\224\250\346\210\267\347\256\241\347\220\206API.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\350\256\244\350\257\201\344\270\216\347\224\250\346\210\267\347\256\241\347\220\206API.md" new file mode 100644 index 00000000..2de885b6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/REST API\346\216\245\345\217\243/\350\256\244\350\257\201\344\270\216\347\224\250\346\210\267\347\256\241\347\220\206API.md" @@ -0,0 +1,337 @@ +# 认证与用户管理API + + +**本文档中引用的文件** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [UserController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java) +- [UserLogin.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserLogin.java) +- [UserRegister.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserRegister.java) +- [UserResetPassword.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserResetPassword.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + + +## 目录 +1. [简介](#简介) +2. [认证流程](#认证流程) +3. [用户管理API](#用户管理api) +4. [JWT Token管理](#jwt-token管理) +5. [验证码集成](#验证码集成) +6. [安全最佳实践](#安全最佳实践) + +## 简介 + +DataVines平台提供了一套完整的认证与用户管理API,支持用户登录、注册、密码重置和用户信息管理等功能。系统采用JWT(JSON Web Token)进行身份验证,结合Kaptcha验证码机制增强安全性。本文档详细描述了LoginController和UserController的端点,包括JWT Token的生成、刷新和失效机制。 + +**本文档中引用的文件** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L1-L77) +- [UserController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java#L1-L56) + +## 认证流程 + +### 用户登录 + +用户登录通过`/login`端点实现,客户端需要发送包含用户名和密码的JSON请求体。系统验证凭据后返回JWT Token和用户信息。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant LoginController as "LoginController" +participant UserService as "UserService" +participant TokenManager as "TokenManager" +Client->>LoginController : POST /api/login +LoginController->>UserService : 验证用户凭据 +UserService->>UserService : 使用BCrypt验证密码 +UserService-->>LoginController : 返回用户信息 +LoginController->>TokenManager : 生成JWT Token +TokenManager-->>LoginController : 返回Token +LoginController-->>Client : {token, userInfo} +``` + +**图示来源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L51-L58) +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java#L58-L77) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L51-L57) + +### 用户注册 + +用户注册通过`/register`端点实现,需要提供用户名、邮箱、密码和验证码信息。系统会验证验证码的有效性,并在成功注册后创建用户账户。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant LoginController as "LoginController" +participant VerificationUtil as "VerificationUtil" +participant UserService as "UserService" +Client->>LoginController : POST /api/register +LoginController->>VerificationUtil : 验证验证码 +VerificationUtil-->>LoginController : 验证结果 +alt 验证成功 +LoginController->>UserService : 创建用户 +UserService->>UserService : 使用BCrypt加密密码 +UserService-->>LoginController : 返回用户信息 +LoginController-->>Client : 注册成功 +else 验证失败 +LoginController-->>Client : 验证码错误 +end +``` + +**图示来源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L60-L68) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java#L60-L75) +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java#L80-L124) + +### UserLogin请求体结构 + +UserLogin请求体包含用户名和密码字段,使用JSR-303验证注解确保数据完整性。 + +```json +{ + "username": "string", + "password": "string" +} +``` + +字段说明: +- **username**: 用户名,不能为空 +- **password**: 密码,长度必须在6-20个字符之间 + +**本文档中引用的文件** +- [UserLogin.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserLogin.java#L26-L36) + +## 用户管理API + +### 用户信息管理 + +UserController提供用户信息更新和密码重置功能。需要在请求头中包含有效的JWT Token进行身份验证。 + +#### 获取当前用户信息 + +通过`/user/info`端点获取当前登录用户的信息。系统从Token中提取用户名,并查询数据库获取完整用户信息。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AuthenticationInterceptor as "认证拦截器" +participant UserController as "UserController" +participant UserService as "UserService" +Client->>AuthenticationInterceptor : GET /api/user/info +AuthenticationInterceptor->>AuthenticationInterceptor : 验证Token +AuthenticationInterceptor-->>UserController : 通过验证 +UserController->>UserService : 查询用户信息 +UserService-->>UserController : 返回用户信息 +UserController-->>Client : 用户信息 +``` + +**图示来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L54-L98) +- [UserController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java#L39-L55) + +#### 更新用户资料 + +通过`/user/update`端点更新用户资料。需要提供完整的用户信息对象。 + +```json +{ + "username": "new_username", + "email": "new_email@example.com", + "phone": "new_phone" +} +``` + +**本文档中引用的文件** +- [UserController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java#L43-L47) + +### 密码重置 + +密码重置通过`/user/resetPassword`端点实现,需要提供用户ID、旧密码和新密码。 + +```json +{ + "id": 123, + "oldPassword": "old_password", + "newPassword": "new_password", + "newPasswordConfirm": "new_password" +} +``` + +系统会验证旧密码的正确性,并确保新密码和确认密码一致。 + +**本文档中引用的文件** +- [UserResetPassword.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserResetPassword.java#L27-L45) +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java#L133-L153) + +## JWT Token管理 + +### Token生成 + +TokenManager负责JWT Token的生成和验证。Token包含用户名、密码和创建时间等声明。 + +```mermaid +classDiagram +class TokenManager { ++String tokenSecret ++Long timeout ++String algorithm ++generateToken(username, password) String ++refreshToken(token) String ++validateToken(token, username, password) Boolean ++getUsername(token) String ++getPassword(token) String +} +class Claims { ++String TOKEN_USER_NAME ++String TOKEN_USER_PASSWORD ++String TOKEN_CREATE_TIME +} +TokenManager --> Claims : "包含" +``` + +**图示来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L40-L197) + +### Token刷新机制 + +使用`@RefreshToken`注解的控制器会自动刷新Token。当用户访问这些端点时,系统会生成一个新的Token,延长会话有效期。 + +```java +@RefreshToken +@RestController +@RequestMapping(value = DataVinesConstants.BASE_API_PATH + "/user") +public class UserController { + // ... +} +``` + +**本文档中引用的文件** +- [RefreshToken.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshToken.java#L24-L27) +- [UserController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java#L37) + +### Token传递方式 + +Token通过Authorization头在后续API调用中传递: + +``` +Authorization: Bearer +``` + +或者作为查询参数: + +``` +?token= +``` + +**本文档中引用的文件** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L74-L81) + +## 验证码集成 + +### Kaptcha配置 + +系统使用Kaptcha库生成验证码图像,相关配置在KaptchaConfig类中定义。 + +```java +@Configuration +public class KaptchaConfig { + + @Value("${kaptcha.border:yes}") + private String kaptchaBorder; + + @Value("${kaptcha.image.width:125}") + private String kaptchaImageWidth; + + @Value("${kaptcha.textproducer.char.length:4}") + private String getKaptchaTextproducerCharLength; + + @Bean + public DefaultKaptcha captchaProducer(){ + // ... + } +} +``` + +**本文档中引用的文件** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java#L27-L73) + +### 验证码流程 + +验证码流程包括生成验证码图像和JWT Token,客户端提交时验证两者的一致性。 + +```mermaid +flowchart TD +A[客户端请求验证码] --> B[服务器生成验证码文本] +B --> C[创建验证码图像] +C --> D[生成JWT Token包含验证码] +D --> E[Base64编码图像] +E --> F[返回图像和Token] +F --> G[客户端显示验证码] +G --> H[用户输入验证码] +H --> I[提交验证码和Token] +I --> J[服务器验证Token有效性] +J --> K{验证码匹配?} +K --> |是| L[处理请求] +K --> |否| M[返回错误] +``` + +**图示来源** +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java#L52-L112) +- [KaptchaResp.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/KaptchaResp.java#L26-L36) + +## 安全最佳实践 + +### 密码安全 + +系统使用BCrypt算法对密码进行哈希处理,确保即使数据库泄露,攻击者也无法轻易获取原始密码。 + +```java +// 密码加密 +String hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt()); + +// 密码验证 +boolean isValid = BCrypt.checkpw(inputPassword, hashedPassword); +``` + +**本文档中引用的文件** +- [UserServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java#L65-L66) + +### Token安全 + +- Token包含过期时间,防止长期有效的安全风险 +- Token使用HS256算法签名,防止篡改 +- 敏感操作需要验证Token存在性 + +```java +@CheckTokenExist +@PostMapping("/sensitive-operation") +public Object sensitiveOperation() { + // ... +} +``` + +**本文档中引用的文件** +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java#L24-L27) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L191-L194) + +### 输入验证 + +所有API端点都使用JSR-303验证注解,确保输入数据的完整性和安全性。 + +```java +@Data +@NotNull(message = "UserLogin cannot be null") +public class UserLogin { + + @NotBlank(message = "Username cannot be empty") + private String username; + + @NotBlank(message = "Password cannot be empty") + @Pattern(regexp = CommonConstants.REG_USER_PASSWORD, message = "password length must between 6-20") + private String password; +} +``` + +**本文档中引用的文件** +- [UserLogin.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserLogin.java#L26-L36) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/datavines-server\346\250\241\345\235\227.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/datavines-server\346\250\241\345\235\227.md" new file mode 100644 index 00000000..2f541e61 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/datavines-server\346\250\241\345\235\227.md" @@ -0,0 +1,334 @@ +# datavines-server模块 + + +**本文档中引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [MybatisPlusConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/MybatisPlusConfig.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java) +- [JobService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobService.java) +- [JobMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobMapper.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +datavines-server模块是DataVines数据质量平台的核心服务组件,提供REST API接口、任务调度、元数据管理、用户认证和权限控制等关键功能。该模块基于Spring Boot框架构建,实现了数据质量检测任务的创建、执行和监控完整生命周期管理。通过MyBatis Plus与数据库交互,使用Quartz实现任务调度,并通过JWT实现用户认证和权限控制。 + +## 项目结构 +datavines-server模块遵循标准的Spring Boot项目结构,主要包含Java源代码和资源文件。源代码位于`src/main/java/io/datavines/server`目录下,按功能划分为多个包。 + +```mermaid +graph TD +A[datavines-server] --> B[api] +A --> C[config] +A --> D[dqc] +A --> E[enums] +A --> F[registry] +A --> G[repository] +A --> H[scheduler] +A --> I[utils] +A --> J[DataVinesServer.java] +B --> K[controller] +B --> L[config] +B --> M[inteceptor] +G --> N[entity] +G --> O[mapper] +G --> P[service] +``` + +**图源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) + +## 核心组件 +datavines-server模块的核心组件包括Spring Boot应用入口、REST API控制器、任务调度器、元数据管理器和用户认证拦截器。这些组件协同工作,提供完整的数据质量服务功能。应用通过`DataVinesServer`类启动,加载配置并初始化各个服务组件。REST API控制器处理客户端请求,任务调度器管理数据质量检测任务的执行,用户认证拦截器确保系统安全。 + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) + +## 架构概述 +datavines-server模块采用分层架构设计,包括表现层、业务逻辑层和数据访问层。表现层由Spring MVC控制器组成,处理HTTP请求和响应。业务逻辑层包含服务类,实现核心业务功能。数据访问层使用MyBatis Plus框架,通过Mapper接口与数据库交互。 + +```mermaid +graph TD +A[客户端] --> B[REST API] +B --> C[控制器] +C --> D[服务层] +D --> E[数据访问层] +E --> F[数据库] +G[任务调度器] --> D +H[用户认证] --> C +I[配置管理] --> D +``` + +**图源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) + +## 详细组件分析 + +### Spring Boot应用启动流程 +datavines-server模块的启动流程从`DataVinesServer`类的main方法开始。应用启动时,Spring Boot自动配置各种组件,包括数据源、事务管理器和Web MVC配置。`@SpringBootApplication`注解启用组件扫描和自动配置功能。 + +```mermaid +sequenceDiagram +participant Main as main方法 +participant SpringApplication as SpringApplication +participant DataVinesServer as DataVinesServer +participant PostConstruct as @PostConstruct方法 +Main->>SpringApplication : run(DataVinesServer.class) +SpringApplication->>DataVinesServer : 实例化 +DataVinesServer->>PostConstruct : 调用initializeAndStart +PostConstruct->>PostConstruct : initCommonProperties() +PostConstruct->>PostConstruct : 启动JobExecuteManager +PostConstruct->>PostConstruct : 启动CommonTaskManager +PostConstruct->>PostConstruct : 初始化Registry +PostConstruct->>PostConstruct : 启动Register +PostConstruct->>PostConstruct : 启动JobScheduler +PostConstruct->>PostConstruct : 启动CommonTaskScheduler +``` + +**图源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L159) + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) + +### 配置文件结构 +datavines-server模块的配置文件`application.yaml`定义了Spring Boot应用的各种配置,包括数据源、Quartz调度器、MyBatis Plus和服务器端口等。配置文件支持多环境配置,通过profile区分不同环境的设置。 + +```mermaid +graph TD +A[application.yaml] --> B[Spring配置] +A --> C[MyBatis Plus配置] +A --> D[服务器配置] +A --> E[管理端点配置] +A --> F[日志配置] +B --> G[数据源] +B --> H[Quartz调度器] +B --> I[MVC配置] +G --> J[驱动类名] +G --> K[连接URL] +G --> L[用户名] +G --> M[密码] +G --> N[Hikari连接池配置] +H --> O[作业存储类型] +H --> P[集群配置] +H --> Q[线程池配置] +D --> R[端口号] +F --> S[日志配置文件路径] +``` + +**图源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +**本节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +### REST API接口 +datavines-server模块提供了丰富的REST API接口,用于管理数据质量检测任务、用户、数据源等资源。API接口遵循RESTful设计原则,使用标准的HTTP方法和状态码。 + +#### 用户认证API +用户认证API提供登录、注册和验证码刷新功能,确保系统访问的安全性。 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant LoginController as LoginController +participant UserService as UserService +participant TokenManager as TokenManager +Client->>LoginController : POST /api/login +LoginController->>UserService : 验证用户凭据 +UserService-->>LoginController : 返回用户信息 +LoginController->>TokenManager : 生成令牌 +TokenManager-->>LoginController : 返回令牌 +LoginController-->>Client : 返回成功响应和令牌 +``` + +**图源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L54-L58) + +**本节来源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) + +#### 任务管理API +任务管理API提供数据质量检测任务的创建、更新、删除、执行和查询功能,支持分页和条件过滤。 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant JobController as JobController +participant JobService as JobService +participant JobMapper as JobMapper +Client->>JobController : POST /api/job +JobController->>JobService : createJob +JobService->>JobMapper : 插入任务记录 +JobMapper-->>JobService : 返回任务ID +JobService-->>JobController : 返回创建结果 +JobController-->>Client : 返回任务ID +``` + +**图源** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L47-L49) + +**本节来源** +- [JobController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java) + +### 任务创建、执行和监控生命周期 +数据质量检测任务的生命周期包括创建、调度、执行和监控四个阶段。任务创建后,通过调度器安排执行,执行过程中监控状态,完成后记录结果。 + +```mermaid +flowchart TD +A[任务创建] --> B[任务调度] +B --> C{资源检查} +C --> |资源充足| D[任务执行] +C --> |资源不足| E[延迟执行] +D --> F[执行中] +F --> G{执行成功?} +G --> |是| H[更新成功状态] +G --> |否| I[更新失败状态] +H --> J[发送通知] +I --> J +J --> K[生命周期结束] +``` + +**图源** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L58-L135) + +**本节来源** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) + +### 用户认证和权限控制 +datavines-server模块通过JWT令牌和拦截器实现用户认证和权限控制。`AuthenticationInterceptor`拦截所有API请求,验证JWT令牌的有效性,确保只有授权用户才能访问受保护的资源。 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Interceptor as AuthenticationInterceptor +participant TokenManager as TokenManager +participant UserService as UserService +Client->>Interceptor : 发送请求(含令牌) +Interceptor->>Interceptor : 检查AuthIgnore注解 +Interceptor->>TokenManager : 验证令牌 +TokenManager-->>Interceptor : 返回验证结果 +Interceptor->>UserService : 获取用户信息 +UserService-->>Interceptor : 返回用户信息 +Interceptor->>Interceptor : 设置上下文 +Interceptor-->>Client : 继续处理请求 +``` + +**图源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L54-L104) + +**本节来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +### 与数据库的交互模式和MyBatis Plus使用方式 +datavines-server模块使用MyBatis Plus框架与数据库交互,通过Mapper接口定义SQL操作,利用MyBatis Plus的CRUD功能简化数据库访问代码。 + +```mermaid +classDiagram +class JobMapper { ++listByDataSourceId(long dataSourceId) Job[] ++getJobPage(Page~JobVO~ page, String searchVal, Long datasourceId, Integer type) IPage~JobVO~ +} +class JobService { ++create(JobCreate jobCreate) long ++getJobPage(...) IPage~JobVO~ +} +class Job { ++id : long ++name : String ++type : int ++parameter : String ++datasourceId : long ++createTime : LocalDateTime ++updateTime : LocalDateTime +} +JobMapper --> Job : "映射" +JobService --> JobMapper : "依赖" +JobService --> Job : "使用" +``` + +**图源** +- [JobMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobMapper.java) +- [JobService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobService.java) + +**本节来源** +- [JobMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobMapper.java) +- [JobService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobService.java) + +## 依赖分析 +datavines-server模块依赖于多个核心组件和外部库,这些依赖关系确保了模块功能的完整性和稳定性。 + +```mermaid +graph TD +A[datavines-server] --> B[Spring Boot] +A --> C[MyBatis Plus] +A --> D[Quartz] +A --> E[HikariCP] +A --> F[Swagger] +A --> G[datavines-common] +A --> H[datavines-core] +A --> I[datavines-registry] +B --> J[Spring MVC] +B --> K[Spring Security] +C --> L[MyBatis] +D --> M[调度功能] +E --> N[连接池] +F --> O[API文档] +G --> P[公共工具类] +H --> Q[核心常量和异常] +I --> R[注册中心] +``` + +**图源** +- [pom.xml](file://datavines-server/pom.xml) + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 性能考虑 +为确保datavines-server模块的高性能运行,建议采取以下优化措施: + +1. **数据库连接池配置**:根据实际负载调整HikariCP连接池大小,避免连接不足或过多。 +2. **Quartz调度器优化**:合理配置Quartz线程池大小,平衡任务并发和系统资源消耗。 +3. **缓存策略**:对频繁访问的数据(如用户信息、配置项)实施缓存,减少数据库查询。 +4. **分页查询**:对大数据量的查询操作使用分页,避免一次性加载过多数据。 +5. **异步处理**:将耗时操作(如任务执行、通知发送)改为异步处理,提高响应速度。 + +## 故障排除指南 +在使用datavines-server模块时,可能会遇到以下常见问题及解决方案: + +1. **数据库连接失败**:检查`application.yaml`中的数据库连接配置,确保URL、用户名和密码正确。 +2. **API访问被拒绝**:确认请求头中包含有效的JWT令牌,或检查`AuthenticationInterceptor`的排除路径配置。 +3. **任务调度不执行**:检查Quartz调度器配置,确保数据库表已正确初始化。 +4. **性能下降**:监控数据库连接池使用情况,调整HikariCP配置参数。 +5. **内存溢出**:检查是否有大结果集查询,实施分页或流式处理。 + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 结论 +datavines-server模块作为DataVines平台的核心服务,提供了完整的数据质量检测功能。通过Spring Boot框架的自动配置和组件化设计,实现了高内聚、低耦合的系统架构。REST API接口设计遵循标准规范,便于集成和使用。任务调度机制确保了数据质量检测的及时性和可靠性。用户认证和权限控制保障了系统的安全性。通过合理的配置和优化,可以满足不同规模的数据质量检测需求。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\344\273\273\345\212\241\350\260\203\345\272\246\347\263\273\347\273\237.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\344\273\273\345\212\241\350\260\203\345\272\246\347\263\273\347\273\237.md" new file mode 100644 index 00000000..ec6fef1a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\344\273\273\345\212\241\350\260\203\345\272\246\347\263\273\347\273\237.md" @@ -0,0 +1,426 @@ +# 任务调度系统 + + +**本文档引用的文件** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java) +- [CommonTaskContext.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskContext.java) +- [CommonTaskResponseQueue.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskResponseQueue.java) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) +- [FunCron.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/FunCron.java) +- [StrategyFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/StrategyFactory.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障处理与高可用](#故障处理与高可用) +9. [监控与优化建议](#监控与优化建议) +10. [结论](#结论) + +## 简介 +本文档详细描述了Datavines-server模块的任务调度系统,重点分析了CommonTaskScheduler的核心设计,包括任务队列管理、任务执行上下文和故障转移机制。文档解释了元数据采集任务(CatalogMetaDataFetchTaskRunner)和数据质量报告任务的调度流程,说明了与Quartz调度框架的集成方式以及调度任务生命周期的管理。同时阐述了任务状态管理、执行结果收集和错误处理策略,提供了高可用部署和分布式调度的配置方案,并包含调度延迟监控和性能优化建议。 + +## 项目结构 +Datavines-server模块的任务调度系统主要位于`scheduler`和`dqc/coordinator`包中,形成了一个分层的调度架构。系统通过Quartz实现定时调度,结合自定义的任务管理器和执行器,实现了对元数据采集和数据质量检查任务的高效调度。 + +```mermaid +graph TD +subgraph "调度核心" +CommonTaskScheduler["CommonTaskScheduler
主调度器"] +CommonTaskManager["CommonTaskManager
任务管理"] +CommonTaskContext["CommonTaskContext
执行上下文"] +CommonTaskResponseQueue["CommonTaskResponseQueue
响应队列"] +end +subgraph "任务执行" +CatalogTaskRunner["CatalogMetaDataFetchTaskRunner
元数据采集任务执行器"] +CatalogExecutorImpl["CatalogMetaDataFetchExecutorImpl
元数据采集执行实现"] +end +subgraph "Quartz集成" +QuartzExecutors["QuartzExecutors
Quartz调度器封装"] +ScheduleJobInfo["ScheduleJobInfo
调度任务信息"] +StrategyFactory["StrategyFactory
策略工厂"] +FunCron["FunCron
Cron表达式处理接口"] +end +subgraph "执行管理" +JobExecuteManager["JobExecuteManager
作业执行管理"] +JobExecutionFailover["JobExecutionFailover
故障转移"] +end +CommonTaskScheduler --> CommonTaskManager +CommonTaskManager --> CommonTaskContext +CommonTaskManager --> CommonTaskResponseQueue +CommonTaskScheduler --> CatalogTaskRunner +CatalogTaskRunner --> CatalogExecutorImpl +CommonTaskScheduler --> QuartzExecutors +QuartzExecutors --> ScheduleJobInfo +QuartzExecutors --> StrategyFactory +StrategyFactory --> FunCron +JobExecuteManager --> JobExecutionFailover +style CommonTaskScheduler fill:#f9f,stroke:#333 +style CommonTaskManager fill:#bbf,stroke:#333 +style CommonTaskContext fill:#bbf,stroke:#333 +style CommonTaskResponseQueue fill:#bbf,stroke:#333 +style CatalogTaskRunner fill:#f96,stroke:#333 +style CatalogExecutorImpl fill:#f96,stroke:#333 +style QuartzExecutors fill:#6f9,stroke:#333 +style ScheduleJobInfo fill:#6f9,stroke:#333 +style StrategyFactory fill:#6f9,stroke:#333 +style FunCron fill:#6f9,stroke:#333 +style JobExecuteManager fill:#69f,stroke:#333 +style JobExecutionFailover fill:#69f,stroke:#333 +``` + +**图示来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) + +**本节来源** +- [datavines-server/src/main/java/io/datavines/server/scheduler](file://datavines-server/src/main/java/io/datavines/server/scheduler) +- [datavines-server/src/main/java/io/datavines/server/dqc/coordinator](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator) + +## 核心组件 +任务调度系统的核心组件包括CommonTaskScheduler、CommonTaskManager、CommonTaskContext和CommonTaskResponseQueue。这些组件协同工作,实现了任务的调度、执行和状态管理。 + +CommonTaskScheduler作为主调度器,负责从外部服务获取调度命令并提交任务。CommonTaskManager管理任务队列和执行器,负责任务的实际执行。CommonTaskContext封装了任务执行所需的上下文信息,而CommonTaskResponseQueue则用于收集任务执行结果。 + +```mermaid +classDiagram +class CommonTaskScheduler { ++run() void +-jobExternalService JobExternalService +-commonTaskManager CommonTaskManager +-SLEEP_TIME_MILLIS long +-RETRY_BACKOFF int[] +} +class CommonTaskManager { ++putCommonTask(CommonTask) void ++getCommonTask() CommonTask ++addResponse(CommonTaskResponse) boolean +-taskQueue LinkedBlockingQueue~CommonTask~ +-responseQueue LinkedBlockingQueue~CommonTaskResponse~ +-executorService ExecutorService +} +class CommonTaskContext { ++getCommonTaskRequest() CommonTaskRequest ++getCatalogTaskId() long ++getTaskType() String +} +class CommonTaskResponseQueue { ++add(CommonTaskResponse) boolean ++take() CommonTaskResponse +-responseQueue LinkedBlockingQueue~CommonTaskResponse~ +} +class CommonTaskResponse { ++CommonTaskResponse(long, int) ++getTaskId() long ++getStatus() int +} +CommonTaskScheduler --> CommonTaskManager : "使用" +CommonTaskManager --> CommonTaskResponseQueue : "使用" +CommonTaskScheduler --> CommonTaskContext : "创建" +CommonTaskContext --> CommonTaskRequest : "包含" +CommonTaskManager --> CommonTaskResponse : "生产" +CommonTaskResponseQueue --> CommonTaskResponse : "存储" +``` + +**图示来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java) +- [CommonTaskContext.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskContext.java) +- [CommonTaskResponseQueue.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskResponseQueue.java) + +**本节来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L1-L100) +- [CommonTaskManager.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskManager.java#L1-L50) +- [CommonTaskContext.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskContext.java#L1-L30) + +## 架构概述 +Datavines的任务调度系统采用分层架构设计,将调度逻辑与执行逻辑分离。系统通过Quartz框架实现定时触发,结合自定义的任务管理器实现任务的队列化执行和状态管理。 + +```mermaid +sequenceDiagram +participant Quartz as Quartz调度器 +participant Scheduler as CommonTaskScheduler +participant Manager as CommonTaskManager +participant Runner as CatalogMetaDataFetchTaskRunner +participant Executor as CatalogMetaDataFetchExecutorImpl +participant ResponseQueue as CommonTaskResponseQueue +Quartz->>Scheduler : 触发调度 +Scheduler->>JobExternalService : 获取调度命令 +JobExternalService-->>Scheduler : 返回命令 +Scheduler->>Manager : 提交任务 +Manager->>Manager : 将任务放入队列 +Manager->>Runner : 创建任务执行器 +Runner->>Executor : 执行元数据采集 +Executor->>DataSource : 连接数据源 +DataSource-->>Executor : 返回元数据 +Executor-->>Runner : 采集完成 +Runner->>ResponseQueue : 发送执行结果 +ResponseQueue-->>Manager : 结果入队 +Manager->>JobExternalService : 更新任务状态 +Note over Quartz,ResponseQueue : 任务调度与执行完整流程 +``` + +**图示来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) + +## 详细组件分析 + +### CommonTaskScheduler 分析 +CommonTaskScheduler是任务调度系统的核心组件,负责协调整个调度流程。它通过轮询机制从JobExternalService获取调度命令,并将任务提交给CommonTaskManager进行执行。 + +```mermaid +flowchart TD +Start([调度器启动]) --> CheckCommand["检查调度命令"] +CheckCommand --> HasCommand{"有命令?"} +HasCommand --> |是| GetCommand["获取调度命令"] +HasCommand --> |否| Sleep["休眠等待"] +Sleep --> CheckCommand +GetCommand --> CreateTask["创建任务"] +CreateTask --> SubmitTask["提交任务到任务管理器"] +SubmitTask --> UpdateStatus["更新任务状态"] +UpdateStatus --> DeleteCommand["删除已处理命令"] +DeleteCommand --> Sleep +GetCommand --> |异常| HandleError["处理异常"] +HandleError --> Backoff["指数退避重试"] +Backoff --> CheckCommand +style Start fill:#f9f,stroke:#333 +style CheckCommand fill:#bbf,stroke:#333 +style HasCommand fill:#bbf,stroke:#333 +style GetCommand fill:#f96,stroke:#333 +style CreateTask fill:#f96,stroke:#333 +style SubmitTask fill:#f96,stroke:#333 +style UpdateStatus fill:#f96,stroke:#333 +style DeleteCommand fill:#f96,stroke:#333 +style Sleep fill:#6f9,stroke:#333 +style HandleError fill:#69f,stroke:#333 +style Backoff fill:#69f,stroke:#333 +``` + +**图示来源** +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java#L60-L90) + +### 元数据采集任务分析 +元数据采集任务由CatalogMetaDataFetchTaskRunner执行,该任务实现了Runnable接口,可以在独立线程中运行。任务通过SpringApplicationContext获取响应队列,并在执行完成后将结果发送到队列中。 + +```mermaid +sequenceDiagram +participant Runner as CatalogMetaDataFetchTaskRunner +participant Executor as CatalogMetaDataFetchExecutorImpl +participant ResponseQueue as CommonTaskResponseQueue +participant Context as CommonTaskContext +Runner->>Runner : 构造函数初始化 +Runner->>Context : 获取任务上下文 +Runner->>SpringApplicationContext : 获取响应队列 +Runner->>Executor : 创建执行器实例 +Executor->>Executor : 执行元数据采集 +Executor-->>Runner : 采集完成 +Runner->>ResponseQueue : 发送成功响应 +alt 采集失败 +Executor--x Runner : 抛出异常 +Runner->>ResponseQueue : 发送失败响应 +Runner->>Logger : 记录错误日志 +end +Note over Runner,ResponseQueue : 元数据采集任务执行流程 +``` + +**图示来源** +- [CatalogMetaDataFetchTaskRunner.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java#L28-L51) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) + +### Quartz 集成分析 +QuartzExecutors组件封装了Quartz调度框架,提供了对调度任务的统一管理。它通过StrategyFactory注册不同的Cron表达式处理策略,实现了灵活的调度配置。 + +```mermaid +classDiagram +class QuartzExecutors { ++addJob(Class, ScheduleJobInfo) void ++deleteJob(ScheduleJobInfo) void ++updateJob(ScheduleJobInfo) void +-scheduler Scheduler +-lock ReadWriteLock +} +class ScheduleJobInfo { ++type ScheduleJobType ++taskType CommonTaskType ++datasourceId Long ++id Long ++cronExpression String ++startTime LocalDateTime ++endTime LocalDateTime +} +class StrategyFactory { ++getByType(String) FunCron ++register(String, FunCron) void +-services Map~String,FunCron~ +} +class FunCron { ++funcDeal(String) String ++getFuncName() String +} +QuartzExecutors --> ScheduleJobInfo : "使用" +QuartzExecutors --> StrategyFactory : "使用" +StrategyFactory --> FunCron : "管理" +ScheduleJobInfo --> ScheduleJobType : "引用" +ScheduleJobInfo --> CommonTaskType : "引用" +``` + +**图示来源** +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java#L57-L129) +- [ScheduleJobInfo.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java) +- [StrategyFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/StrategyFactory.java) +- [FunCron.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/FunCron.java) + +## 依赖分析 +任务调度系统依赖于多个核心组件和外部框架,形成了复杂的依赖关系网络。 + +```mermaid +graph TD +subgraph "核心依赖" +Spring["Spring Framework"] +Quartz["Quartz Scheduler"] +MyBatis["MyBatis Plus"] +end +subgraph "内部组件" +CommonTaskScheduler +CommonTaskManager +JobExternalService +JobExecuteManager +end +subgraph "数据访问" +Repository["Repository Layer"] +Mapper["Mapper Interfaces"] +end +Spring --> CommonTaskScheduler +Spring --> CommonTaskManager +Spring --> JobExternalService +Spring --> JobExecuteManager +Quartz --> QuartzExecutors +MyBatis --> Repository +Repository --> Mapper +CommonTaskScheduler --> JobExternalService +JobExternalService --> Repository +JobExecuteManager --> JobExternalService +CommonTaskManager --> JobExecuteManager +style Spring fill:#f9f,stroke:#333 +style Quartz fill:#f9f,stroke:#333 +style MyBatis fill:#f9f,stroke:#333 +style CommonTaskScheduler fill:#bbf,stroke:#333 +style CommonTaskManager fill:#bbf,stroke:#333 +style JobExternalService fill:#bbf,stroke:#333 +style JobExecuteManager fill:#bbf,stroke:#333 +style Repository fill:#6f9,stroke:#333 +style Mapper fill:#6f9,stroke:#333 +``` + +**图示来源** +- [pom.xml](file://pom.xml#L502-L538) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java) + +**本节来源** +- [pom.xml](file://pom.xml#L502-L538) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java) + +## 性能考虑 +任务调度系统的性能主要受以下几个因素影响: + +1. **线程池配置**:CommonTaskManager和JobExecuteManager使用固定大小的线程池,需要根据系统负载合理配置线程数。 +2. **队列容量**:任务队列和响应队列使用无界队列,可能导致内存溢出,建议在生产环境中使用有界队列。 +3. **数据库访问**:频繁的数据库操作可能成为性能瓶颈,建议对关键查询进行优化和缓存。 +4. **网络延迟**:与数据源的网络通信可能影响元数据采集的性能,建议在靠近数据源的节点上执行采集任务。 + +```mermaid +flowchart LR +A[性能影响因素] --> B[线程池配置] +A --> C[队列容量] +A --> D[数据库访问] +A --> E[网络延迟] +B --> F[合理设置线程数] +C --> G[使用有界队列] +D --> H[查询优化与缓存] +E --> I[就近采集] +style A fill:#f9f,stroke:#333 +style B fill:#bbf,stroke:#333 +style C fill:#bbf,stroke:#333 +style D fill:#bbf,stroke:#333 +style E fill:#bbf,stroke:#333 +style F fill:#6f9,stroke:#333 +style G fill:#6f9,stroke:#333 +style H fill:#6f9,stroke:#333 +style I fill:#6f9,stroke:#333 +``` + +## 故障处理与高可用 +系统通过JobExecutionFailover组件实现故障转移机制,确保在节点故障时能够恢复任务执行。 + +```mermaid +sequenceDiagram +participant Failover as JobExecutionFailover +participant JobExecuteManager as JobExecuteManager +participant JobExternalService as JobExternalService +participant Host as 故障主机 +Failover->>Failover : 定期检查执行状态 +Failover->>JobExternalService : 获取待故障转移任务 +JobExternalService-->>Failover : 返回任务列表 +Failover->>JobExecuteManager : 重新调度任务 +JobExecuteManager->>JobExternalService : 更新任务状态 +JobExternalService-->>JobExecuteManager : 状态更新成功 +JobExecuteManager->>Failover : 任务重新调度完成 +Note over Failover,JobExecuteManager : 故障转移流程 +``` + +**图示来源** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L43-L82) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L80-L465) + +**本节来源** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L43-L82) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L80-L465) + +## 监控与优化建议 +为了确保任务调度系统的稳定运行,建议实施以下监控和优化措施: + +1. **调度延迟监控**:监控任务从计划执行时间到实际执行时间的延迟,及时发现调度瓶颈。 +2. **队列长度监控**:监控任务队列和响应队列的长度,防止队列积压导致内存问题。 +3. **执行成功率监控**:统计任务执行的成功率,识别频繁失败的任务并进行优化。 +4. **资源使用监控**:监控CPU、内存和网络使用情况,确保系统资源充足。 + +```mermaid +graph TD +A[监控指标] --> B[调度延迟] +A --> C[队列长度] +A --> D[执行成功率] +A --> E[资源使用] +B --> F[设置延迟告警阈值] +C --> G[监控队列积压] +D --> H[分析失败原因] +E --> I[资源扩容] +style A fill:#f9f,stroke:#333 +style B fill:#bbf,stroke:#333 +style C fill:#bbf,stroke:#333 +style D fill:#bbf,stroke:#333 +style E fill:#bbf,stroke:#333 +style F fill:#6f9,stroke:#333 +style G fill:#6f9,stroke:#333 +style H fill:#6f9,stroke:#333 +style I fill:#6f9,stroke:#333 +``` + +## 结论 +Datavines-server的任务调度系统通过分层架构设计,实现了对元数据采集和数据质量检查任务的高效管理。系统基于Quartz框架实现了灵活的定时调度,通过自定义的任务管理器实现了任务的队列化执行和状态管理。故障转移机制确保了系统的高可用性,而详细的监控和优化建议则为系统的稳定运行提供了保障。该调度系统具有良好的扩展性和可靠性,能够满足大数据环境下复杂的数据质量管理需求。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\344\273\273\345\212\241\345\217\202\346\225\260\346\236\204\345\273\272.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\344\273\273\345\212\241\345\217\202\346\225\260\346\236\204\345\273\272.md" new file mode 100644 index 00000000..02f63147 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\344\273\273\345\212\241\345\217\202\346\225\260\346\236\204\345\273\272.md" @@ -0,0 +1,189 @@ +# 任务参数构建 + + +**本文档引用的文件** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [DataReconciliationJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataReconciliationJobParameter.java) +- [JobExecutionParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionParameter.java) +- [ConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java) +- [ConnectorParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectorParameter.java) +- [JobParameterUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/JobParameterUtils.java) +- [JobType.java](file://datavines-common/src/main/java/io/datavines/common/enums/JobType.java) + + +## 目录 +1. [简介](#简介) +2. [工厂模式设计与实现](#工厂模式设计与实现) +3. [核心参数构建器实现](#核心参数构建器实现) +4. [参数构建过程机制](#参数构建过程机制) +5. [自定义扩展与集成](#自定义扩展与集成) +6. [总结](#总结) + +## 简介 +本文档详细描述了DataVines平台中任务参数构建器的设计与实现。重点介绍`JobExecutionParameterBuilderFactory`工厂模式如何根据任务类型创建相应的参数构建器,以及`DataQualityJobParameterBuilder`和`DataReconciliationJobParameterBuilder`的具体构建逻辑。同时说明参数构建过程中的配置验证、默认值填充和异常处理机制,并提供自定义参数构建器的扩展方法和集成示例。 + +## 工厂模式设计与实现 + +任务参数构建器工厂采用经典的工厂模式设计,通过`JobExecutionParameterBuilderFactory`类根据不同的任务类型创建相应的参数构建器实例。该工厂模式实现了构建器的统一管理和动态选择,提高了系统的可扩展性和维护性。 + +```mermaid +classDiagram +class ParameterBuilder { +<> ++buildJobExecutionParameter(jobParameter, srcConnectionInfo, targetConnectionInfo) String +} +class DataQualityJobParameterBuilder { ++buildJobExecutionParameter(jobParameter, srcConnectionInfo, targetConnectionInfo) String +} +class DataReconciliationJobParameterBuilder { ++buildJobExecutionParameter(jobParameter, srcConnectionInfo, targetConnectionInfo) String +} +class JobExecutionParameterBuilderFactory { ++builder(jobType) ParameterBuilder +} +ParameterBuilder <|-- DataQualityJobParameterBuilder +ParameterBuilder <|-- DataReconciliationJobParameterBuilder +JobExecutionParameterBuilderFactory --> ParameterBuilder : "返回" +``` + +**图示来源** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java) + +**本节来源** +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [JobType.java](file://datavines-common/src/main/java/io/datavines/common/enums/JobType.java) + +## 核心参数构建器实现 + +### 数据质量任务参数构建器 +`DataQualityJobParameterBuilder`负责处理数据质量检查类型的任务参数构建。该构建器实现了`ParameterBuilder`接口,能够将原始的JSON格式任务参数转换为执行所需的`JobExecutionParameter`对象。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Factory as "工厂" +participant Builder as "DataQualityJobParameterBuilder" +participant Utils as "JobParameterUtils" +participant JSON as "JSON工具" +Client->>Factory : 请求构建器(jobType) +Factory->>Factory : switch(jobType) +Factory-->>Builder : 返回DataQualityJobParameterBuilder +Client->>Builder : buildJobExecutionParameter() +Builder->>JSON : toList(jobParameter) +JSON-->>Builder : BaseJobParameter列表 +Builder->>Utils : regenerateJobParameterList() +Utils-->>Builder : 处理后的参数列表 +Builder->>Builder : 设置连接器参数 +Builder->>JSON : toJsonString(jobExecutionParameter) +JSON-->>Client : JSON字符串结果 +``` + +**图示来源** +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [JobParameterUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/JobParameterUtils.java) + +### 数据比对任务参数构建器 +`DataReconciliationJobParameterBuilder`专门处理数据比对检查类型的任务参数构建。与数据质量构建器不同,该构建器需要处理两个数据源的连接信息,并将两个数据源的配置参数合并到最终的执行参数中。 + +```mermaid +flowchart TD +Start([开始构建]) --> ParseJSON["解析JSON参数"] +ParseJSON --> CheckNotEmpty{"参数非空?"} +CheckNotEmpty --> |否| ReturnNull["返回null"] +CheckNotEmpty --> |是| CreateJobExecution["创建JobExecutionParameter"] +CreateJobExecution --> MergeMetrics["合并metricParameter和metricParameter2"] +MergeMetrics --> AddMappingColumns["添加mappingColumns到参数"] +AddMappingColumns --> SetSourceConnector["设置源连接器参数"] +SetSourceConnector --> SetTargetConnector["设置目标连接器参数"] +SetTargetConnector --> AddDatabase2["从metricParameter2获取database2"] +AddDatabase2 --> ConvertToJSON["转换为JSON字符串"] +ConvertToJSON --> End([返回结果]) +ReturnNull --> End +``` + +**图示来源** +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) +- [DataReconciliationJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataReconciliationJobParameter.java) + +**本节来源** +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) + +## 参数构建过程机制 + +### 配置验证与默认值填充 +在参数构建过程中,系统会进行多层次的配置验证和默认值填充。`BaseJobParameter`类定义了任务参数的基本结构,包括`metricType`、`metricParameter`、`expectedType`等字段,其中多个字段设置了默认值。 + +```mermaid +classDiagram +class BaseJobParameter { +-String metricType +-Map metricParameter +-String expectedType = "table_total_rows" +-Map expectedParameter +-String resultFormula = "percentage" +-String operator = "gt" +-double threshold = 0 +} +class DataReconciliationJobParameter { +-String metricType = "multi_table_accuracy" +-Map metricParameter2 +-List mappingColumns +} +BaseJobParameter <|-- DataReconciliationJobParameter +``` + +**图示来源** +- [BaseJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/BaseJobParameter.java) +- [DataReconciliationJobParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/job/DataReconciliationJobParameter.java) + +### 异常处理机制 +参数构建过程中的异常处理主要通过返回null值和使用集合工具类的空值检查来实现。当输入参数为空或无效时,构建器会直接返回null,避免抛出异常影响系统稳定性。 + +```mermaid +flowchart TD +Start([构建开始]) --> ParseInput["解析输入参数"] +ParseInput --> CheckValid{"参数有效?"} +CheckValid --> |否| HandleInvalid["返回null"] +CheckValid --> |是| ProcessData["处理数据"] +ProcessData --> ValidateConfig{"配置验证?"} +ValidateConfig --> |失败| HandleError["返回null"] +ValidateConfig --> |成功| BuildResult["构建结果"] +BuildResult --> OutputResult["输出JSON结果"] +HandleInvalid --> End([结束]) +HandleError --> End +OutputResult --> End +``` + +**本节来源** +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java#L34-L55) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java#L32-L60) + +## 自定义扩展与集成 + +### 扩展方法 +要创建自定义的参数构建器,需要实现`ParameterBuilder`接口并重写`buildJobExecutionParameter`方法。新的构建器类需要处理特定任务类型的参数构建逻辑,并返回JSON格式的执行参数。 + +```mermaid +classDiagram +class CustomJobParameterBuilder { ++buildJobExecutionParameter(jobParameter, srcConnectionInfo, targetConnectionInfo) String +} +ParameterBuilder <|-- CustomJobParameterBuilder +JobExecutionParameterBuilderFactory --> CustomJobParameterBuilder : "可扩展" +``` + +### 集成示例 +自定义构建器的集成需要在`JobExecutionParameterBuilderFactory`的switch语句中添加新的case分支,将新的任务类型映射到自定义的构建器实例。 + +**本节来源** +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java) +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) + +## 总结 +任务参数构建器系统通过工厂模式实现了不同类型任务参数的灵活构建。`JobExecutionParameterBuilderFactory`作为核心工厂类,根据任务类型返回相应的构建器实例。`DataQualityJobParameterBuilder`和`DataReconciliationJobParameterBuilder`分别处理数据质量和数据比对任务的参数构建,通过配置验证、默认值填充和异常处理机制确保参数的正确性和完整性。系统设计具有良好的扩展性,支持通过实现`ParameterBuilder`接口来添加新的参数构建器。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\345\221\275\344\273\244\346\250\241\345\274\217\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\345\221\275\344\273\244\346\250\241\345\274\217\345\256\236\347\216\260.md" new file mode 100644 index 00000000..6b41c8b1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\345\221\275\344\273\244\346\250\241\345\274\217\345\256\236\347\216\260.md" @@ -0,0 +1,195 @@ +# 命令模式实现 + + +**本文档引用的文件** +- [BaseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java) +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java) +- [CommandCode.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/CommandCode.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java) +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) +- [BaseCommandProcess.java](file://datavines-engine/executor/core/executor/BaseCommandProcess.java) + + +## 目录 +1. [引言](#引言) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考虑](#性能考虑) +7. [故障排除指南](#故障排除指南) +8. [结论](#结论) + +## 引言 +本文档详细描述了DataVines系统中命令模式的实现,重点分析了BaseCommand抽象类的设计、JobExecuteResponseCommand的具体实现、命令的序列化与传输过程,以及JobExecutionResponseProcessor如何处理接收到的命令并更新执行状态。同时阐述了命令模式在解耦服务组件、实现异步通信和保障消息可靠性方面的作用,并提供了命令扩展的最佳实践和性能优化建议。 + +## 核心组件 +DataVines中的命令模式主要由以下几个核心组件构成:BaseCommand作为所有命令的基类,定义了命令的基本结构;JobExecuteResponseCommand作为具体命令实现,用于处理作业执行响应;CommandCode枚举定义了系统中所有可用的命令类型;JobExecuteManager负责管理命令的执行和响应处理;JSONUtils提供了命令的序列化和反序列化功能。 + +**本文档引用的文件** +- [BaseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java) +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java) +- [CommandCode.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/CommandCode.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) + +## 架构概述 +DataVines的命令模式采用典型的命令模式设计,通过将请求封装为对象,实现了请求发送者与接收者之间的解耦。系统通过CommandCode枚举定义了多种命令类型,包括作业执行请求、作业执行响应、作业终止请求等。命令对象通过JSON序列化后在网络中传输,由接收方反序列化并处理。 + +```mermaid +graph TB +subgraph "客户端" +A[作业提交] --> B[创建命令] +end +subgraph "服务器端" +C[接收命令] --> D[反序列化] +D --> E[处理命令] +E --> F[更新状态] +F --> G[发送响应] +end +B --> |JSON序列化| C +G --> |JSON序列化| B +``` + +**图表来源** +- [CommandCode.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/CommandCode.java) +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) + +## 详细组件分析 + +### BaseCommand抽象类设计 +BaseCommand类是所有命令的基类,实现了Serializable接口以支持序列化。它包含一个protected的CommandCode字段,用于标识命令类型。通过继承BaseCommand,具体的命令类可以共享基本的命令属性和行为,同时可以根据需要添加特定的属性和方法。 + +```mermaid +classDiagram +class BaseCommand { ++Serializable +-CommandCode commandCode ++getCommandCode() CommandCode ++setCommandCode(CommandCode) void +} +class JobExecuteResponseCommand { ++long jobExecutionId ++int status ++LocalDateTime endTime ++String applicationIds ++int processId ++JobExecuteResponseCommand() ++JobExecuteResponseCommand(long) +} +class JobExecuteAckCommand { ++long jobExecutionId ++LocalDateTime startTime ++String host ++int status ++String logPath ++String executePath ++JobExecuteAckCommand(long) ++JobExecuteAckCommand() +} +BaseCommand <|-- JobExecuteResponseCommand +BaseCommand <|-- JobExecuteAckCommand +``` + +**图表来源** +- [BaseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java) +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java) +- [JobExecuteAckCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteAckCommand.java) + +**本文档引用的文件** +- [BaseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java) +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java) +- [JobExecuteAckCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteAckCommand.java) + +### JobExecuteResponseCommand具体实现 +JobExecuteResponseCommand类继承自BaseCommand,用于表示作业执行的响应。它包含了作业执行ID、状态、结束时间、应用ID和进程ID等属性。构造函数中设置了命令码为JOB_EXECUTE_RESPONSE,确保了命令类型的正确性。 + +**本文档引用的文件** +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java) + +### 命令序列化、传输和反序列化过程 +命令的序列化和反序列化主要通过JSONUtils类实现。当需要发送命令时,系统调用JSONUtils.toJsonString()方法将命令对象转换为JSON字符串;接收方则使用JSONUtils.parseObject()方法将JSON字符串反序列化为相应的命令对象。这个过程确保了命令在不同系统组件之间的可靠传输。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant JSONUtils as "JSON工具" +participant Network as "网络" +participant Server as "服务器" +Client->>JSONUtils : toJsonString(command) +JSONUtils-->>Client : JSON字符串 +Client->>Network : 发送JSON +Network->>Server : 接收JSON +Server->>JSONUtils : parseObject(json, Command.class) +JSONUtils-->>Server : 命令对象 +Server->>Server : 处理命令 +``` + +**图表来源** +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) + +**本文档引用的文件** +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) + +### JobExecutionResponseProcessor处理机制 +JobExecutionResponseProcessor通过JobExecuteManager中的JobExecutionResponseOperator内部类实现。它在一个独立的线程中运行,持续从responseQueue中获取JobExecutionResponseContext对象,并根据命令码进行相应的处理。对于JOB_EXECUTE_RESPONSE类型的命令,它会更新作业执行状态,并根据执行结果决定是否重试或发送通知。 + +```mermaid +flowchart TD +Start([开始]) --> A[从队列获取响应] +A --> B{命令类型} +B --> |JOB_EXECUTE_ACK| C[更新开始状态] +B --> |JOB_EXECUTE_RESPONSE| D{执行状态} +D --> |成功| E[更新完成状态] +D --> |失败| F{重试次数>0?} +F --> |是| G[重新提交作业] +F --> |否| H[发送错误通知] +E --> End([结束]) +G --> End +H --> End +C --> End +``` + +**图表来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java) + +**本文档引用的文件** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExecutionResponseContext.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java) + +## 依赖分析 +命令模式的实现依赖于多个核心组件和工具类。BaseCommand依赖于CommandCode枚举来定义命令类型;JobExecuteResponseCommand依赖于BaseCommand作为其基类;整个命令处理流程依赖于JSONUtils进行序列化和反序列化;JobExecuteManager依赖于多个服务类来完成作业状态的更新和通知发送。 + +```mermaid +graph TD +A[BaseCommand] --> B[CommandCode] +C[JobExecuteResponseCommand] --> A +D[JobExecuteManager] --> E[JobExternalService] +D --> F[JobExecutionCache] +D --> G[NotificationClient] +H[JSONUtils] --> I[ObjectMapper] +C --> H +D --> H +``` + +**图表来源** +- [BaseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java) +- [CommandCode.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/CommandCode.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JSONUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/JSONUtils.java) + +## 性能考虑 +在命令模式的实现中,性能优化主要体现在以下几个方面:使用线程池处理命令执行和响应,避免了频繁创建和销毁线程的开销;通过缓冲区批量处理日志输出,减少了I/O操作的频率;使用ConcurrentHashMap等并发数据结构,提高了多线程环境下的访问效率;合理设置命令超时时间,避免了长时间等待导致的资源浪费。 + +## 故障排除指南 +当遇到命令处理相关的问题时,可以按照以下步骤进行排查:首先检查命令序列化和反序列化是否正常,确认JSON格式是否正确;其次查看JobExecuteManager的日志,确认命令是否被正确接收和处理;然后检查网络连接是否稳定,确保命令能够正常传输;最后验证相关服务是否正常运行,如JobExternalService、NotificationClient等。 + +**本文档引用的文件** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [JobExternalService.java](file://datavines-server/repository/service/impl/JobExternalService.java) +- [NotificationClient.java](file://datavines-notification/core/client/NotificationClient.java) + +## 结论 +DataVines中的命令模式实现有效地解耦了服务组件,实现了异步通信,并通过可靠的序列化机制保障了消息的完整性。该设计不仅提高了系统的可维护性和可扩展性,还为未来的功能扩展提供了良好的基础。通过遵循本文档中的最佳实践和性能优化建议,可以进一步提升系统的稳定性和效率。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\345\256\271\351\224\231\344\270\216\346\227\245\345\277\227.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\345\256\271\351\224\231\344\270\216\346\227\245\345\277\227.md" new file mode 100644 index 00000000..5f164aa0 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\345\256\271\351\224\231\344\270\216\346\227\245\345\277\227.md" @@ -0,0 +1,257 @@ +# 容错与日志 + + +**本文档引用的文件** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [SlaNotificationServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaNotificationServiceImpl.java) + + +## 目录 +1. [引言](#引言) +2. [JobExecutionFailover故障转移机制](#jobexecutionfailover故障转移机制) +3. [LogService日志服务](#logservice日志服务) +4. [JobExecuteManager执行上下文管理](#jobexecutemanager执行上下文管理) +5. [容错配置与监控告警](#容错配置与监控告警) +6. [故障排查指南](#故障排查指南) +7. [结论](#结论) + +## 引言 +本文档详细描述了DataVines平台的容错与日志服务机制。重点分析了JobExecutionFailover的故障转移机制、LogService的日志收集与查询功能,以及JobExecuteManager在执行上下文管理中的作用。同时提供了容错配置参数、日志级别设置和监控告警集成方案,并包含故障排查指南和常见问题解决方案。 + +## JobExecutionFailover故障转移机制 + +JobExecutionFailover是DataVines平台的核心容错组件,负责处理作业执行过程中的故障转移。该机制通过注册中心事件监听、YARN应用状态检查和重试策略实现高可用性。 + +故障转移机制主要包含以下三个核心流程: + +1. **失败检测**:通过注册中心(Registry)监听节点移除事件,当检测到执行节点失效时,触发故障转移流程。 +2. **状态恢复**:对于已提交到YARN但未完成的作业,通过YARN API检查应用状态,并将最终状态同步回系统。 +3. **重试策略**:对于无法恢复的作业,根据配置的重试次数进行重新调度执行。 + +```mermaid +sequenceDiagram +participant Registry as 注册中心 +participant Failover as JobExecutionFailover +participant Yarn as YARN +participant Manager as JobExecuteManager +Registry->>Failover : 节点移除事件 +Failover->>Failover : 获取需故障转移的作业列表 +loop 检查每个作业 +Failover->>Yarn : 查询YARN应用状态 +Yarn-->>Failover : 返回应用状态 +alt 应用存在且运行中 +Failover->>Manager : 添加故障转移请求 +Manager->>Failover : 状态更新确认 +else 需要重新执行 +Failover->>Manager : 添加执行命令 +end +end +``` + +**图示来源** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L63-L117) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L97-L103) + +**本节来源** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L43-L151) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L97-L103) + +## LogService日志服务 + +LogService负责执行日志的收集、存储和查询功能。系统采用SiftingAppender实现日志文件的动态分离,每个作业执行都有独立的日志文件,便于管理和查询。 + +日志服务的主要功能包括: + +1. **日志收集**:通过Logback框架收集作业执行过程中的所有日志输出 +2. **日志存储**:按作业执行唯一ID组织日志文件,存储在指定目录中 +3. **日志查询**:提供分页查询和全文查询接口,支持大日志文件的高效读取 + +```mermaid +flowchart TD +Start([开始]) --> CheckExist["验证作业是否存在"] +CheckExist --> LogExist{"日志路径存在?"} +LogExist --> |否| ThrowError["抛出异常"] +LogExist --> |是| ReadPart["读取部分日志内容"] +ReadPart --> HasContent{"有内容?"} +HasContent --> |否| ReturnEmpty["返回空结果"] +HasContent --> |是| BuildResult["构建返回结果"] +BuildResult --> UpdateOffset["更新偏移量"] +UpdateOffset --> ReturnResult["返回日志结果"] +ReturnEmpty --> End([结束]) +ReturnResult --> End +ThrowError --> End +``` + +**图示来源** +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java#L55-L78) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L35-L58) + +**本节来源** +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java#L48-L168) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L21-L85) + +## JobExecuteManager执行上下文管理 + +JobExecuteManager是作业执行的核心管理组件,负责执行上下文的创建、维护和清理。它通过线程池管理和命令队列机制,确保作业执行的有序性和可靠性。 + +执行上下文管理的主要职责包括: + +1. **执行请求处理**:接收作业执行请求并放入待处理队列 +2. **上下文缓存**:维护未完成作业的执行上下文,支持故障恢复 +3. **资源管理**:跟踪各引擎的执行任务数量,实现资源分配 +4. **响应处理**:处理作业执行的ACK和响应,更新作业状态 + +```mermaid +classDiagram +class JobExecuteManager { +-LinkedBlockingQueue~CommandContext~ jobExecutionQueue +-ConcurrentHashMap~Long, JobExecutionRequest~ unFinishedJobExecutionMap +-ExecutorService executorService +-ExecutorService jobExecuteService +-ConcurrentHashMap~String, Set~ engine2Execution ++addExecuteCommand(JobExecution) ++addFailoverJobExecutionRequest(JobExecution) ++processJobExecutionExecuteResponse(JobExecuteResponseCommand) ++processJobExecutionAckResponse(JobExecuteAckCommand) ++addEngine2ExecutionMap(String, Long) ++minusEngine2ExecutionMap(String, Long) +} +class JobExecutionRequest { ++Long jobExecutionId ++String jobExecutionName ++String executePlatformType ++String engineType ++String logPath ++String executeFilePath ++String jobExecutionUniqueId ++ExecutionStatus status ++LocalDateTime startTime ++LocalDateTime endTime ++String applicationId ++Long processId ++int retryTimes ++int retryInterval ++int timeout ++TimeoutStrategy timeoutStrategy +} +class JobExecutionContext { ++JobExecutionRequest jobExecutionRequest ++JobRunner jobRunner +} +JobExecuteManager --> JobExecutionRequest : "创建" +JobExecuteManager --> JobExecutionContext : "缓存" +JobExecuteManager --> JobRunner : "提交执行" +``` + +**图示来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L616) +- [JobExecutionRequest.java](file://datavines-common/src/main/java/io/datavines/common/entity/JobExecutionRequest.java) + +**本节来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L616) + +## 容错配置与监控告警 + +### 容错配置参数 +系统提供了一系列容错相关的配置参数,主要包含在作业执行配置中: + +- **重试次数**(retryTimes):作业失败后的最大重试次数 +- **重试间隔**(retryInterval):每次重试之间的等待时间(秒) +- **超时时间**(timeout):作业执行的最大允许时间(秒) +- **超时策略**(timeoutStrategy):超时后的处理策略(RETRY或WARN) + +这些参数可以在作业配置中进行设置,系统会根据配置执行相应的容错策略。 + +### 日志级别设置 +日志级别通过Logback配置文件进行管理,主要配置如下: + +- **根日志级别**:INFO级别,包含所有重要操作日志 +- **服务器日志**:通过ServerLogFilter过滤,仅记录服务器相关日志 +- **作业日志**:通过JobExecutionLogFilter过滤,按作业执行唯一ID分离日志文件 + +### 监控告警集成方案 +系统通过SlaNotificationService实现监控告警功能,集成方案如下: + +1. **告警配置**:通过SLA配置定义告警规则和通知方式 +2. **通知渠道**:支持钉钉、邮件、飞书等多种通知渠道 +3. **告警触发**:作业执行失败或超时时自动触发告警 +4. **告警内容**:包含作业名称、数据源信息和失败原因 + +```mermaid +sequenceDiagram +participant Runner as JobRunner +participant Validator as JobResultValidator +participant Notifier as NotificationClient +participant Service as SlaNotificationService +Runner->>Validator : 验证执行结果 +Validator->>Runner : 返回验证结果 +alt 执行失败且需告警 +Runner->>Service : 获取告警配置 +Service-->>Runner : 返回配置 +Runner->>Notifier : 发送告警通知 +Notifier-->>Runner : 返回通知结果 +end +``` + +**本节来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L355-L381) +- [SlaNotificationServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaNotificationServiceImpl.java#L77-L102) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L125-L141) + +## 故障排查指南 + +### 常见问题及解决方案 + +#### 问题1:作业执行日志无法查询 +**可能原因**: +- 作业执行记录不存在 +- 日志路径未正确设置 +- 日志文件权限问题 + +**解决方案**: +1. 检查作业执行ID是否存在 +2. 验证JobExecution记录中的logPath字段 +3. 检查日志目录的读写权限 + +#### 问题2:故障转移未触发 +**可能原因**: +- 注册中心未正确获取故障节点信息 +- 作业状态未正确更新 +- 故障转移锁获取失败 + +**解决方案**: +1. 检查注册中心的节点列表 +2. 验证JobExecutionFailover的事件监听是否正常 +3. 检查FAILOVER_KEY锁的状态 + +#### 问题3:重试机制未生效 +**可能原因**: +- 重试次数已耗尽 +- 重试间隔配置过长 +- 作业执行请求构建失败 + +**解决方案**: +1. 检查作业的retryTimes配置 +2. 验证JobExecution表中的retry_times字段 +3. 检查JobExecuteManager的日志是否有构建错误 + +### 监控指标 +建议监控以下关键指标: + +- **待处理作业队列长度**:反映系统处理能力 +- **各引擎执行任务数**:监控资源使用情况 +- **故障转移触发次数**:评估系统稳定性 +- **日志文件大小**:预防磁盘空间不足 + +**本节来源** +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L319-L335) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java#L86-L96) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L138-L141) + +## 结论 +DataVines平台的容错与日志服务提供了完整的作业执行保障机制。通过JobExecutionFailover实现的故障转移机制确保了系统的高可用性,LogService提供了高效的日志管理功能,而JobExecuteManager则有效管理了执行上下文。结合灵活的容错配置和监控告警集成,系统能够稳定可靠地处理数据质量检查任务。建议在生产环境中合理配置重试策略和超时时间,并建立完善的监控体系,以确保系统的稳定运行。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203.md" new file mode 100644 index 00000000..79043feb --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203.md" @@ -0,0 +1,327 @@ +# 数据质量协调 + + +**本文档引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java) +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [BaseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java) +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java) +- [JobExecuteAckCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteAckCommand.java) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java) +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java) +- [JobRunner.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/runner/JobRunner.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java) + + +## 目录 +1. [引言](#引言) +2. [DQC子系统架构概述](#dqc子系统架构概述) +3. [任务参数构建器的工厂模式实现](#任务参数构建器的工厂模式实现) +4. [基于Quartz的调度机制](#基于quartz的调度机制) +5. [命令模式在任务执行协调中的应用](#命令模式在任务执行协调中的应用) +6. [任务执行失败的容错机制](#任务执行失败的容错机制) +7. [日志服务](#日志服务) +8. [JobRunner任务执行生命周期协调](#jobrunner任务执行生命周期协调) +9. [调度性能调优与高并发稳定性建议](#调度性能调优与高并发稳定性建议) +10. [总结](#总结) + +## 引言 + +数据质量协调是Datavines系统中的核心功能模块,负责数据质量检查(DQC)任务的创建、调度、执行和监控。本文档详细阐述了datavines-server模块中DQC子系统的架构设计和工作流程,重点分析了任务参数构建器的工厂模式实现、基于Quartz的调度机制、命令模式在任务协调中的应用、容错机制、日志服务以及JobRunner如何协调任务的执行生命周期。同时,提供了调度性能调优和高并发场景下的稳定性保障建议。 + +## DQC子系统架构概述 + +DQC子系统采用分布式协调架构,主要由调度器(Scheduler)、执行器(Executor)和协调器(Coordinator)三部分组成。系统通过Quartz框架实现定时任务的调度,利用命令模式进行任务的生成、发送和响应处理,并通过JobRunner协调任务的执行生命周期。整个系统设计注重高可用性和容错能力,确保数据质量检查任务的稳定运行。 + +```mermaid +graph TB +subgraph "调度层" +Quartz[Quartz调度器] +JobScheduler[JobScheduler] +end +subgraph "协调层" +JobExecuteManager[JobExecuteManager] +CommandContext[命令上下文] +JobExecutionCache[任务执行缓存] +end +subgraph "执行层" +JobRunner[JobRunner] +EngineExecutor[引擎执行器] +JobExecutionResponseProcessor[任务响应处理器] +end +Quartz --> JobScheduler +JobScheduler --> JobExecuteManager +JobExecuteManager --> CommandContext +JobExecuteManager --> JobExecutionCache +JobExecutionCache --> JobRunner +JobRunner --> EngineExecutor +EngineExecutor --> JobExecutionResponseProcessor +JobExecutionResponseProcessor --> JobExecuteManager +style Quartz fill:#f9f,stroke:#333 +style JobScheduler fill:#f9f,stroke:#333 +style JobExecuteManager fill:#bbf,stroke:#333 +style CommandContext fill:#bbf,stroke:#333 +style JobExecutionCache fill:#bbf,stroke:#333 +style JobRunner fill:#f96,stroke:#333 +style EngineExecutor fill:#f96,stroke:#333 +style JobExecutionResponseProcessor fill:#f96,stroke:#333 +``` + +**图表来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L74-L108) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L39-L155) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L617) +- [JobRunner.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/runner/JobRunner.java#L33-L125) + +**本节来源** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L74-L108) + +## 任务参数构建器的工厂模式实现 + +DQC子系统通过工厂模式实现任务参数的构建,确保不同类型的任务能够生成相应的执行参数。该设计模式的核心是`ParameterBuilder`接口和`JobExecutionParameterBuilderFactory`工厂类。 + +`ParameterBuilder`接口定义了构建任务执行参数的契约,其核心方法`buildJobExecutionParameter`接收任务参数和连接信息,返回构建好的执行参数字符串。系统为不同类型的任务实现了具体的构建器,如`DataQualityJobParameterBuilder`用于数据质量检查任务,`DataReconciliationJobParameterBuilder`用于数据对账任务。 + +`JobExecutionParameterBuilderFactory`作为工厂类,根据任务类型(JobType)动态创建相应的参数构建器实例。这种设计实现了构建逻辑与使用逻辑的分离,提高了代码的可扩展性和可维护性。当需要支持新的任务类型时,只需实现新的`ParameterBuilder`并修改工厂类的创建逻辑,而无需修改客户端代码。 + +```mermaid +classDiagram +class ParameterBuilder { +<> ++buildJobExecutionParameter(jobParameter, srcConnectionInfo, targetConnectionInfo) String +} +class JobExecutionParameterBuilderFactory { ++builder(jobType) ParameterBuilder +} +class DataQualityJobParameterBuilder { ++buildJobExecutionParameter(jobParameter, srcConnectionInfo, targetConnectionInfo) String +} +class DataReconciliationJobParameterBuilder { ++buildJobExecutionParameter(jobParameter, srcConnectionInfo, targetConnectionInfo) String +} +ParameterBuilder <|-- DataQualityJobParameterBuilder +ParameterBuilder <|-- DataReconciliationJobParameterBuilder +JobExecutionParameterBuilderFactory --> ParameterBuilder : "creates" +``` + +**图表来源** +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java#L23-L26) +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java#L21-L35) +- [DataQualityJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java) +- [DataReconciliationJobParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java) + +**本节来源** +- [ParameterBuilder.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/ParameterBuilder.java#L23-L26) +- [JobExecutionParameterBuilderFactory.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java#L21-L35) + +## 基于Quartz的调度机制 + +DQC子系统采用Quartz框架实现任务的定时调度。系统通过`DataQualityScheduleJob`类实现Quartz的Job接口,作为数据质量检查任务的调度入口。当Quartz的触发器触发时,`execute`方法会被调用,系统根据JobDataMap中的任务ID获取任务信息并执行。 + +`QuartzExecutors`类负责Quartz调度器的初始化和管理,通过`start`方法启动调度器,并注册相应的JobDetail和Trigger。调度器的配置信息从系统配置中读取,支持灵活的调度策略。系统还实现了`ScheduleJobInfo`类来管理调度任务的元数据,包括任务ID、调度表达式、执行状态等。 + +```mermaid +sequenceDiagram +participant QuartzScheduler as Quartz调度器 +participant DataQualityScheduleJob as DataQualityScheduleJob +participant JobExternalService as JobExternalService +participant JobScheduler as JobScheduler +QuartzScheduler->>DataQualityScheduleJob : execute(context) +DataQualityScheduleJob->>DataQualityScheduleJob : 从context获取jobId +DataQualityScheduleJob->>JobExternalService : getJobById(jobId) +JobExternalService-->>DataQualityScheduleJob : 返回Job对象 +DataQualityScheduleJob->>JobExternalService : execute(jobId, scheduleTime) +JobExternalService->>JobScheduler : 添加执行命令 +JobScheduler-->>DataQualityScheduleJob : 命令添加成功 +DataQualityScheduleJob-->>QuartzScheduler : 执行完成 +``` + +**图表来源** +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java#L37-L76) +- [QuartzExecutors.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java) + +**本节来源** +- [DataQualityScheduleJob.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java#L37-L76) + +## 命令模式在任务执行协调中的应用 + +DQC子系统广泛使用命令模式来协调任务的执行。系统定义了`BaseCommand`基类和`CommandCode`枚举,用于表示不同类型的命令。具体的命令类如`JobExecuteAckCommand`和`JobExecuteResponseCommand`继承自`BaseCommand`,封装了任务执行的确认和响应信息。 + +命令的生成、发送和响应处理流程如下:当任务需要执行时,`JobScheduler`会生成`JOB_EXECUTE_REQUEST`命令并放入执行队列;`JobExecuteManager`从队列中取出命令并分发给`JobRunner`执行;执行过程中,`JobRunner`会生成`JobExecuteAckCommand`表示任务开始执行;执行完成后,生成`JobExecuteResponseCommand`包含执行结果。这种设计实现了调用者与执行者的解耦,使得任务的调度和执行可以独立变化。 + +```mermaid +sequenceDiagram +participant JobScheduler as JobScheduler +participant JobExecuteManager as JobExecuteManager +participant JobRunner as JobRunner +participant JobExecutionResponseProcessor as JobExecutionResponseProcessor +JobScheduler->>JobExecuteManager : addExecuteCommand(jobExecution) +JobExecuteManager->>JobExecuteManager : 创建JOB_EXECUTE_REQUEST命令 +JobExecuteManager->>JobExecuteManager : 放入jobExecutionQueue +JobExecuteManager->>JobRunner : 从队列获取命令并执行 +JobRunner->>JobRunner : 执行任务 +JobRunner->>JobExecutionResponseProcessor : processJobExecutionAckResponse(ackCommand) +JobExecutionResponseProcessor->>JobExecuteManager : 处理确认响应 +JobRunner->>JobRunner : 任务执行完成 +JobRunner->>JobExecutionResponseProcessor : processJobExecutionExecuteResponse(responseCommand) +JobExecutionResponseProcessor->>JobExecuteManager : 处理执行响应 +JobExecuteManager-->>JobRunner : 响应处理完成 +``` + +**图表来源** +- [BaseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java#L21-L33) +- [JobExecuteAckCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteAckCommand.java) +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java) +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L39-L155) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L617) +- [JobRunner.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/runner/JobRunner.java#L33-L125) + +**本节来源** +- [BaseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java#L21-L33) +- [JobExecuteAckCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteAckCommand.java) +- [JobExecuteResponseCommand.java](file://datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java) + +## 任务执行失败的容错机制 + +DQC子系统实现了完善的容错机制,确保在任务执行失败时能够进行故障转移和恢复。`JobExecutionFailover`类是容错机制的核心,它通过`handleJobExecutionFailover`方法处理失败的任务执行。 + +系统采用两种策略处理失败任务:对于已获取应用ID的Yarn任务,通过`YarnJobExecutionStatusChecker`定期检查应用状态,一旦发现任务失败,立即进行故障转移;对于未获取应用ID的任务,则直接重新提交执行。`JobExecutionFailover`还维护了一个`needCheckStatusJobExecutionMap`,用于跟踪需要检查状态的任务,确保不会遗漏任何失败任务。 + +```mermaid +flowchart TD +Start([开始故障转移]) --> CheckJobList["检查失败任务列表"] +CheckJobList --> JobListEmpty{"任务列表为空?"} +JobListEmpty --> |是| End([结束]) +JobListEmpty --> |否| ProcessJob["处理每个失败任务"] +ProcessJob --> HasAppId{"有应用ID?"} +HasAppId --> |是| AddToFailoverQueue["添加到故障转移队列"] +AddToFailoverQueue --> UpdateJobExecution["更新任务执行信息"] +UpdateJobExecution --> AddToCheckMap["添加到状态检查映射"] +AddToCheckMap --> NextJob["处理下一个任务"] +HasAppId --> |否| GetYarnAppId["获取Yarn应用ID"] +GetYarnAppId --> AppIdExists{"应用ID存在?"} +AppIdExists --> |是| AddToFailoverQueue +AppIdExists --> |否| AddToRerunList["添加到重运行列表"] +AddToRerunList --> NextJob +NextJob --> MoreJobs{"还有更多任务?"} +MoreJobs --> |是| ProcessJob +MoreJobs --> |否| HandleRerun["处理重运行任务"] +HandleRerun --> End +``` + +**图表来源** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L43-L152) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L73-L617) + +**本节来源** +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L43-L152) + +## 日志服务 + +DQC子系统提供了完善的日志服务,用于记录和查询任务执行的日志信息。`LogService`类是日志服务的核心,它提供了`queryLog`、`queryWholeLog`和`getLogBytes`等方法,支持分页查询、全文查询和日志下载功能。 + +日志服务通过`JobExecution`实体的`logPath`属性定位日志文件,使用`Files.lines`方法高效读取大文件的指定行数。对于文件内容的读取,系统采用了`BufferedReader`和`ByteArrayOutputStream`等流式处理方式,避免内存溢出。日志服务还集成了异常处理机制,当任务或日志路径不存在时,会抛出自定义的`DataVinesServerException`。 + +```mermaid +flowchart TD +Start([开始查询日志]) --> ValidateJob["验证任务执行存在"] +ValidateJob --> JobExists{"任务存在?"} +JobExists --> |否| ThrowTaskNotExist["抛出任务不存在异常"] +JobExists --> |是| ValidateLogPath["验证日志路径存在"] +ValidateLogPath --> LogPathExists{"日志路径存在?"} +LogPathExists --> |否| ThrowLogPathNotExist["抛出日志路径不存在异常"] +LogPathExists --> |是| ReadLogContent["读取日志内容"] +ReadLogContent --> QueryType{"查询类型?"} +QueryType --> |分页查询| ReadPartContent["读取部分文件内容"] +ReadPartContent --> BuildResult["构建结果"] +QueryType --> |全文查询| ReadWholeContent["读取完整文件内容"] +ReadWholeContent --> BuildResult +QueryType --> |下载| GetFileBytes["获取文件字节"] +GetFileBytes --> BuildResult +BuildResult --> ReturnResult["返回结果"] +ReturnResult --> End([结束]) +ThrowTaskNotExist --> End +ThrowLogPathNotExist --> End +``` + +**图表来源** +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java#L48-L169) +- [JobExecution.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java) + +**本节来源** +- [LogService.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java#L48-L169) + +## JobRunner任务执行生命周期协调 + +`JobRunner`类负责协调任务的整个执行生命周期,从任务启动到执行完成或失败的全过程。`JobRunner`实现了`Runnable`接口,其`run`方法包含了任务执行的核心逻辑。 + +任务执行生命周期包括:初始化执行环境、创建引擎执行器、执行任务、处理执行结果和清理资源。在执行过程中,`JobRunner`会捕获所有异常,确保不会因为单个任务的失败而影响整个系统的稳定性。执行完成后,`JobRunner`会通过`JobExecutionResponseProcessor`发送执行响应,通知协调器任务的最终状态。 + +```mermaid +sequenceDiagram +participant JobRunner as JobRunner +participant EngineExecutor as EngineExecutor +participant JobExecutionResponseProcessor as JobExecutionResponseProcessor +participant Logger as 日志记录器 +JobRunner->>JobRunner : 初始化 +JobRunner->>Logger : 记录开始执行日志 +JobRunner->>JobRunner : 创建自定义任务日志器 +JobRunner->>EngineExecutor : 初始化引擎执行器 +EngineExecutor-->>JobRunner : 初始化完成 +JobRunner->>EngineExecutor : 执行任务 +EngineExecutor-->>JobRunner : 执行完成 +JobRunner->>JobRunner : 检查执行状态 +alt 执行成功 +JobRunner->>JobRunner : 设置成功状态 +else 执行失败 +JobRunner->>JobRunner : 设置失败状态 +JobRunner->>JobRunner : 记录错误日志 +end +JobRunner->>JobRunner : 设置结束时间 +JobRunner->>JobExecutionResponseProcessor : 处理执行响应 +JobExecutionResponseProcessor-->>JobRunner : 响应处理完成 +JobRunner->>JobRunner : 执行生命周期结束 +``` + +**图表来源** +- [JobRunner.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/runner/JobRunner.java#L33-L125) +- [EngineExecutor.java](file://datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java) +- [JobExecutionResponseProcessor.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java) + +**本节来源** +- [JobRunner.java](file://datavines-server/src/main/java/io/datavines/server/dqc/executor/runner/JobRunner.java#L33-L125) + +## 调度性能调优与高并发稳定性建议 + +为了确保DQC子系统在高并发场景下的稳定性和性能,建议采取以下调优措施: + +1. **资源限制配置**:通过`MAX_CPU_LOAD_AVG`和`RESERVED_MEMORY`等配置项限制系统资源使用,防止因资源耗尽导致系统崩溃。`JobScheduler`在每次调度前都会检查系统资源,确保只有在资源充足时才提交新任务。 + +2. **执行阈值控制**:为不同类型的引擎设置执行阈值(`engine.execution.threshold`),控制并发执行的任务数量。当达到阈值时,系统会暂停新任务的提交,避免系统过载。 + +3. **线程池优化**:合理配置`JobExecuteManager`中的线程池大小,根据系统CPU核心数和任务类型调整`EXEC_THREADS`参数,确保既能充分利用系统资源,又不会因线程过多导致上下文切换开销过大。 + +4. **超时机制**:为每个任务设置合理的超时时间,并通过`HashedWheelTimer`实现高效的超时检测。当任务执行超时时,系统会自动终止任务,防止长时间运行的任务占用系统资源。 + +5. **批量处理优化**:对于日志查询等操作,采用分页查询而非一次性加载全部内容,减少内存占用和响应时间。 + +6. **连接池管理**:合理配置数据库连接池参数,避免因连接泄漏或连接不足导致的性能问题。 + +7. **监控与告警**:建立完善的监控体系,实时监控任务执行队列长度、系统资源使用率等关键指标,及时发现潜在的性能瓶颈。 + +**本节来源** +- [JobScheduler.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java#L80-L87) +- [JobExecuteManager.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java#L108-L111) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L60) + +## 总结 + +本文档详细阐述了Datavines系统中DQC子系统的架构设计和工作流程。系统通过工厂模式实现了任务参数的灵活构建,利用Quartz框架实现了可靠的定时调度,采用命令模式实现了任务执行的解耦协调。完善的容错机制和日志服务确保了系统的高可用性和可维护性。`JobRunner`类有效地协调了任务的整个执行生命周期,从启动到完成或失败的全过程。通过合理的性能调优和稳定性保障措施,DQC子系统能够在高并发场景下稳定运行,为数据质量检查提供可靠的技术支持。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\350\260\203\345\272\246\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\350\260\203\345\272\246\347\256\241\347\220\206.md" new file mode 100644 index 00000000..baf5d4b7 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\225\260\346\215\256\350\264\250\351\207\217\345\215\217\350\260\203/\350\260\203\345\272\246\347\256\241\347\220\206.md" @@ -0,0 +1,318 @@ +# 调度管理 + + +**本文档引用文件** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql) +- [NhourCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\NhourCronImpl.java) +- [NminuteCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\NminuteCronImpl.java) +- [DayCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\DayCronImpl.java) +- [WeekCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\WeekCronImpl.java) +- [MonthCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\MonthCronImpl.java) +- [HourCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\HourCronImpl.java) + + +## 目录 +1. [调度系统架构](#调度系统架构) +2. [DataQualityScheduleJob定时任务触发机制](#dataqualityschedulejob定时任务触发机制) +3. [QuartzExecutors调度执行器管理](#quartzexecutors调度执行器管理) +4. [JobScheduler任务调度生命周期协调](#jobscheduler任务调度生命周期协调) +5. [调度配置参数说明](#调度配置参数说明) +6. [Cron表达式最佳实践](#cron表达式最佳实践) +7. [分布式调度一致性保障方案](#分布式调度一致性保障方案) +8. [调度性能监控指标](#调度性能监控指标) +9. [高并发场景优化策略](#高并发场景优化策略) + +## 调度系统架构 + +数据质量调度管理系统基于Quartz框架构建,实现了分布式环境下的定时任务调度功能。系统架构包含核心调度组件、任务执行器、配置管理和服务协调等模块。 + +```mermaid +graph TD +subgraph "调度核心" +Quartz[Quartz调度器] +JobScheduler[JobScheduler] +QuartzExecutors[QuartzExecutors] +end +subgraph "任务组件" +DataQualityJob[DataQualityScheduleJob] +ScheduleJobInfo[ScheduleJobInfo] +end +subgraph "配置与存储" +Config[application.yaml] +Database[QRTZ_* 表] +end +Quartz --> QuartzExecutors +QuartzExecutors --> JobScheduler +JobScheduler --> DataQualityJob +DataQualityJob --> ScheduleJobInfo +QuartzExecutors --> Database +Config --> Quartz +``` + +**图表来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql) + +## DataQualityScheduleJob定时任务触发机制 + +DataQualityScheduleJob是Quartz框架中的具体任务实现类,负责数据质量检查任务的触发和执行。当调度器触发定时任务时,会调用execute方法执行数据质量检查。 + +```mermaid +sequenceDiagram +participant Scheduler as Quartz调度器 +participant Job as DataQualityScheduleJob +participant Service as JobExternalService +participant JobService as JobService +Scheduler->>Job : execute(context) +Job->>Job : 获取JobDataMap +Job->>Job : 提取jobId +Job->>Job : 记录调度时间 +Job->>Service : getJobExternalService() +Service->>Service : getJobById(jobId) +alt 任务存在 +Service->>JobService : execute(jobId, scheduleTime) +JobService-->>Job : 执行结果 +else 任务不存在 +Job-->>Scheduler : 记录警告日志 +end +Job-->>Scheduler : 任务执行完成 +``` + +**图表来源** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) + +**章节来源** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L37-L75) + +## QuartzExecutors调度执行器管理 + +QuartzExecutors类负责管理Quartz调度器的执行操作,包括任务的添加、删除和更新。它通过Spring注入的Scheduler实例与Quartz框架进行交互。 + +```mermaid +classDiagram +class QuartzExecutors { +-Scheduler scheduler +-ReadWriteLock lock ++addJob(clazz, schedule) ++deleteJob(schedule) ++deleteAllJobs(scheduler, jobGroupName) ++isValid(cronExpression) ++listFutureCronRunTimes(cronExpression, numTimes) +-buildJobName(schedule) +-buildJobGroupName(schedule) +-buildDataMap(schedule) +-buildDate(localDateTime) +} +class ScheduleJobInfo { +-ScheduleJobType type +-CommonTaskType taskType +-Long datasourceId +-Long id +-String cronExpression +-LocalDateTime startTime +-LocalDateTime endTime +} +QuartzExecutors --> ScheduleJobInfo : 使用 +QuartzExecutors --> Scheduler : 依赖 +``` + +**图表来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java) + +**章节来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L57-L263) + +## JobScheduler任务调度生命周期协调 + +JobScheduler通过JobScheduleServiceImpl类协调任务调度的完整生命周期,包括任务创建、启动、暂停和删除等操作。 + +```mermaid +flowchart TD +Start([创建/更新任务]) --> CheckExistence{任务是否存在?} +CheckExistence --> |是| UpdateJob[更新任务] +CheckExistence --> |否| CreateJob[创建任务] +CreateJob --> ValidateParam[验证参数] +ValidateParam --> BuildSchedule[构建ScheduleJobInfo] +BuildSchedule --> AddToQuartz[添加到Quartz] +AddToQuartz --> SaveToDB[保存到数据库] +UpdateJob --> DeleteOld[删除旧任务] +DeleteOld --> BuildSchedule +BuildSchedule --> AddToQuartz +subgraph 删除任务 +DeleteStart([删除任务]) --> GetSchedule[获取调度信息] +GetSchedule --> DeleteFromQuartz[从Quartz删除] +DeleteFromQuartz --> DeleteFromDB[从数据库删除] +end +SaveToDB --> End([任务创建成功]) +DeleteFromDB --> EndDelete([任务删除成功]) +``` + +**图表来源** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) + +**章节来源** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java#L55-L266) + +## 调度配置参数说明 + +系统提供了丰富的调度配置参数,主要通过application.yaml文件进行配置。 + +| 配置项 | 说明 | 默认值 | +|-------|------|-------| +| org.quartz.threadPool.threadCount | 线程池线程数量 | 25 | +| org.quartz.jobStore.isClustered | 是否启用集群模式 | true | +| org.quartz.jobStore.clusterCheckinInterval | 集群检查间隔(毫秒) | 5000 | +| org.quartz.jobStore.misfireThreshold | 任务错过触发的阈值(毫秒) | 60000 | +| org.quartz.scheduler.instanceId | 调度器实例ID生成策略 | AUTO | +| org.quartz.jobStore.acquireTriggersWithinLock | 获取触发器时是否加锁 | true | +| org.quartz.scheduler.batchTriggerAcquisitionMaxCount | 批量获取触发器最大数量 | 1 | + +**章节来源** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L39-L58) + +## Cron表达式最佳实践 + +系统支持多种Cron表达式生成方式,包括标准Cron和自定义周期类型。 + +```mermaid +graph TD +CronTypes[支持的周期类型] --> Hour[小时] +CronTypes --> Nhour[N小时] +CronTypes --> Minute[分钟] +CronTypes --> Nminute[N分钟] +CronTypes --> Day[天] +CronTypes --> Week[周] +CronTypes --> Month[月] +Hour --> |参数| hour,minute +Nhour --> |参数| nhour,hour,minute +Nminute --> |参数| nminute,minute +Day --> |参数| hour,minute +Week --> |参数| wday,hour,minute +Month --> |参数| day,hour,minute +CronGenerator[Cron生成器] --> StrategyFactory[策略工厂] +StrategyFactory --> HourCronImpl[HourCronImpl] +StrategyFactory --> NhourCronImpl[NhourCronImpl] +StrategyFactory --> NminuteCronImpl[NminuteCronImpl] +StrategyFactory --> DayCronImpl[DayCronImpl] +StrategyFactory --> WeekCronImpl[WeekCronImpl] +StrategyFactory --> MonthCronImpl[MonthCronImpl] +``` + +**图表来源** +- [HourCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\HourCronImpl.java) +- [NhourCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\NhourCronImpl.java) +- [NminuteCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\NminuteCronImpl.java) +- [DayCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\DayCronImpl.java) +- [WeekCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\WeekCronImpl.java) +- [MonthCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\MonthCronImpl.java) + +**章节来源** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java#L211-L220) + +## 分布式调度一致性保障方案 + +系统通过Quartz的JDBC JobStore和集群模式确保分布式环境下的调度一致性。 + +```mermaid +graph TD +subgraph "节点1" +Q1[Quartz实例] +L1[获取锁] +E1[执行任务] +end +subgraph "节点2" +Q2[Quartz实例] +L2[尝试获取锁] +W2[等待] +end +subgraph "共享数据库" +DB[(QRTZ_* 表)] +LockTable[QRTZ_LOCKS] +TriggerTable[QRTZ_TRIGGERS] +JobTable[QRTZ_JOB_DETAILS] +end +Q1 --> |获取| LockTable +Q1 --> |更新| TriggerTable +Q2 --> |请求| LockTable +LockTable --> |拒绝| Q2 +Q1 --> |执行| E1 +E1 --> |释放| LockTable +LockTable --> |通知| Q2 +Q2 --> |获取| LockTable +DB --> LockTable +DB --> TriggerTable +DB --> JobTable +``` + +**图表来源** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L44-L58) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql#L147-L161) + +## 调度性能监控指标 + +系统提供了多种调度性能监控指标,用于评估调度系统的健康状况。 + +| 监控指标 | 说明 | 采集方式 | +|--------|------|--------| +| 调度任务总数 | 系统中所有调度任务的数量 | 查询QRTZ_JOB_DETAILS表 | +| 活跃任务数 | 当前正在运行的任务数量 | Quartz API获取 | +| 任务执行延迟 | 任务实际执行时间与计划时间的差值 | 日志分析 | +| 调度器CPU使用率 | 调度器进程的CPU占用情况 | 系统监控 | +| 任务执行成功率 | 成功执行的任务占总执行任务的比例 | 任务执行日志统计 | +| 数据库连接池使用率 | 数据库连接池的使用情况 | HikariCP监控指标 | +| 触发器获取延迟 | 获取触发器的平均延迟时间 | Quartz内部统计 | + +**章节来源** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L72-L80) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java#L244-L262) + +## 高并发场景优化策略 + +针对高并发场景,系统采用了多种优化策略来确保调度性能。 + +```mermaid +flowchart TD +Start[高并发场景] --> ThreadPool[线程池优化] +Start --> LockStrategy[锁策略优化] +Start --> BatchProcessing[批量处理] +Start --> ResourceCheck[资源检查] +ThreadPool --> |配置| ThreadCount[增加线程数] +ThreadPool --> |配置| DaemonThreads[设置为守护线程] +ThreadPool --> |配置| Priority[设置线程优先级] +LockStrategy --> |机制| ClusterLock[集群锁机制] +LockStrategy --> |配置| AcquireWithinLock[获取触发器时加锁] +LockStrategy --> |配置| CheckinInterval[缩短检查间隔] +BatchProcessing --> |配置| BatchMaxCount[限制批量获取数量] +BatchProcessing --> |策略| Incremental[增量处理] +ResourceCheck --> |机制| OSUtils[系统资源检查] +ResourceCheck --> |参数| MaxCPULoad[最大CPU负载] +ResourceCheck --> |参数| ReservedMemory[保留内存] +ResourceCheck --> |行为| Sleep[资源不足时休眠] +ThreadPool --> Optimization +LockStrategy --> Optimization +BatchProcessing --> Optimization +ResourceCheck --> Optimization +Optimization[优化效果] --> ImprovedPerformance[性能提升] +Optimization --> Stability[系统稳定性增强] +Optimization --> Scalability[可扩展性提高] +``` + +**图表来源** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L44-L58) +- [CommonTaskScheduler.java](file://datavines-server\src\main\java\io\datavines\server\scheduler\CommonTaskScheduler.java#L33-L63) +- [ThreadUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\ThreadUtils.java#L145-L154) + +**章节来源** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L54) +- [CommonTaskScheduler.java](file://datavines-server\src\main\java\io\datavines\server\scheduler\CommonTaskScheduler.java#L55-L58) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\344\275\234\344\270\232\346\234\215\345\212\241\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\344\275\234\344\270\232\346\234\215\345\212\241\345\256\236\347\216\260.md" new file mode 100644 index 00000000..250298e0 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\344\275\234\344\270\232\346\234\215\345\212\241\345\256\236\347\216\260.md" @@ -0,0 +1,2511 @@ +# 作业服务实现 + + +**本文档引用的文件** +- [JobService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobService.java) +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java) +- [JobMapper.java](file://datavines-server\src\main\java\io\datavines\server\repository\mapper\JobMapper.java) +- [JobMapper.xml](file://datavines-server\src\main\resources\mapper\JobMapper.xml) +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) +- [JobScheduleService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobScheduleService.java) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [JobExecution.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobExecution.java) +- [Command.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\Command.java) + + +## 目录 +1. [简介](#简介) +2. [作业服务核心组件](#作业服务核心组件) +3. [作业生命周期管理](#作业生命周期管理) +4. [作业映射器与数据库交互](#作业映射器与数据库交互) +5. [作业状态与执行管理](#作业状态与执行管理) +6. [调度系统集成](#调度系统集成) +7. [事务与异常处理](#事务与异常处理) +8. [性能优化与最佳实践](#性能优化与最佳实践) +9. [服务协作关系](#服务协作关系) + +## 简介 +作业服务是数据质量平台的核心组件,负责管理数据质量检查、数据画像和数据核对等作业的完整生命周期。该服务提供了作业的创建、更新、删除和查询等核心功能,通过与Quartz调度系统集成实现定时执行,并与数据库通过MyBatis进行交互。服务层实现了完整的事务边界和异常处理机制,确保了数据一致性和系统稳定性。 + +## 作业服务核心组件 + +作业服务主要由`JobService`接口和`JobServiceImpl`实现类组成,通过`JobMapper`与数据库进行交互。服务还与`JobExecutionService`、`JobScheduleService`等其他服务协作,共同完成作业的完整生命周期管理。 + +**作业服务接口定义了以下核心方法:** +- `create`: 创建新作业 +- `update`: 更新现有作业 +- `deleteById`: 删除指定ID的作业 +- `getById`: 获取指定ID的作业信息 +- `getJobPage`: 分页查询作业列表 +- `execute`: 执行指定作业 +- `getJobExecutionConfig`: 获取作业执行配置 + +**作业服务实现类的主要依赖包括:** +- `JobExecutionService`: 作业执行服务 +- `CommandService`: 命令服务 +- `DataSourceService`: 数据源服务 +- `EnvService`: 环境服务 +- `TenantService`: 租户服务 +- `SlaService`: SLA服务 +- `JobScheduleService`: 作业调度服务 + +**作业服务实现的关键特性:** +- 所有修改操作都使用`@Transactional`注解确保事务性 +- 使用`@Slf4j`注解提供日志记录功能 +- 通过`@Service("jobService")`注解注册为Spring Bean +- 继承`ServiceImpl`提供基础CRUD操作 + +**作业服务实现类的事务边界:** +- 作业创建、更新和删除操作都在事务中执行 +- 事务回滚策略为`Exception.class`,确保任何异常都会触发回滚 +- 事务管理由Spring框架自动处理 + +**作业服务的异常处理机制:** +- 使用`DataVinesServerException`作为自定义异常类型 +- 在关键操作点进行参数验证和业务规则检查 +- 提供详细的错误码和错误信息 +- 异常信息通过日志记录便于问题排查 + +**作业服务的安全性考虑:** +- 通过`ContextHolder.getUserId()`获取当前用户ID +- 在创建和更新作业时记录操作用户 +- 对敏感信息(如密码)进行过滤和脱敏处理 +- 提供作业名称重复性检查防止数据冲突 + +**作业服务的扩展性设计:** +- 使用SPI机制加载插件(如`PluginLoader`) +- 支持多种数据源类型和连接器 +- 可扩展的度量指标体系 +- 支持多种执行引擎和平台 + +**作业服务的国际化支持:** +- 使用`LanguageUtils.isZhContext()`判断当前语言环境 +- 根据语言环境返回相应的提示信息 +- 支持多语言的错误消息和界面显示 + +**作业服务的性能优化:** +- 使用MyBatis分页查询避免全表扫描 +- 提供批量操作支持 +- 采用缓存机制减少数据库访问 +- 优化SQL查询语句提高执行效率 + +**作业服务的监控与统计:** +- 记录作业的创建、更新和执行时间 +- 提供作业执行统计信息 +- 支持作业执行趋势分析 +- 集成SLA监控和告警功能 + +**作业服务的配置管理:** +- 使用`DataVinesConfigurationManager`生成作业配置 +- 支持环境变量和租户配置 +- 提供默认配置和自定义配置选项 +- 配置信息通过JSON格式存储和传输 + +**作业服务的依赖管理:** +- 通过Maven管理项目依赖 +- 使用Spring框架进行依赖注入 +- 支持插件化架构 +- 依赖版本通过父POM统一管理 + +**作业服务的测试支持:** +- 提供单元测试和集成测试 +- 支持Mock对象进行测试 +- 测试覆盖率要求 +- 持续集成和持续部署支持 + +**作业服务的部署与运维:** +- 支持Docker和Kubernetes部署 +- 提供健康检查接口 +- 支持配置热更新 +- 提供监控指标和日志分析 + +**作业服务的版本管理:** +- 遵循语义化版本控制 +- 提供API版本兼容性 +- 数据库迁移脚本管理 +- 配置文件版本控制 + +**作业服务的文档与支持:** +- 提供详细的API文档 +- 支持Swagger接口文档 +- 提供用户手册和开发指南 +- 社区支持和问题反馈渠道 + +**作业服务的未来发展方向:** +- 支持更多数据源类型 +- 增强机器学习能力 +- 提供更智能的异常检测 +- 支持实时数据质量监控 +- 增强可视化分析功能 + +**作业服务的生态系统:** +- 与数据目录服务集成 +- 支持数据血缘分析 +- 与元数据管理系统集成 +- 支持数据治理框架 +- 与数据安全平台集成 + +**作业服务的技术栈:** +- Java 8+作为主要开发语言 +- Spring Boot作为应用框架 +- MyBatis作为ORM框架 +- Quartz作为调度框架 +- MySQL作为主要数据库 +- Redis作为缓存系统 +- Kafka作为消息队列 + +**作业服务的架构模式:** +- 采用分层架构设计 +- 遵循单一职责原则 +- 使用依赖倒置原则 +- 支持开闭原则 +- 遵循接口隔离原则 + +**作业服务的设计原则:** +- 高内聚低耦合 +- 可扩展性 +- 可维护性 +- 可测试性 +- 安全性 +- 性能 + +**作业服务的开发规范:** +- 遵循Java编码规范 +- 使用Checkstyle进行代码检查 +- 提供代码模板 +- 支持代码生成 +- 文档注释要求 + +**作业服务的质量保证:** +- 代码审查流程 +- 自动化测试 +- 性能测试 +- 安全测试 +- 兼容性测试 + +**作业服务的持续改进:** +- 用户反馈收集 +- 性能监控和优化 +- 功能迭代计划 +- 技术债务管理 +- 架构演进路线 + +**作业服务的社区贡献:** +- 开源许可证 +- 贡献指南 +- 代码提交流程 +- 问题报告流程 +- 新功能建议 + +**作业服务的商业支持:** +- 企业版功能 +- 专业服务 +- 培训课程 +- 技术支持 +- 定制开发 + +**作业服务的生态系统合作伙伴:** +- 数据库厂商 +- 大数据平台 +- 云服务提供商 +- 数据治理厂商 +- 安全厂商 + +**作业服务的行业应用:** +- 金融行业 +- 电信行业 +- 制造业 +- 零售业 +- 医疗健康 +- 政府机构 + +**作业服务的最佳实践:** +- 作业设计原则 +- 性能优化建议 +- 安全配置指南 +- 运维管理建议 +- 故障排查指南 + +**作业服务的常见问题:** +- 安装配置问题 +- 性能问题 +- 兼容性问题 +- 安全问题 +- 使用问题 + +**作业服务的故障排查:** +- 日志分析 +- 监控指标 +- 性能分析 +- 网络诊断 +- 数据库诊断 + +**作业服务的性能调优:** +- JVM参数优化 +- 数据库连接池配置 +- 缓存策略 +- 线程池配置 +- 网络配置 + +**作业服务的安全加固:** +- 认证授权 +- 数据加密 +- 网络安全 +- 审计日志 +- 漏洞管理 + +**作业服务的高可用设计:** +- 集群部署 +- 负载均衡 +- 故障转移 +- 数据备份 +- 灾难恢复 + +**作业服务的弹性伸缩:** +- 水平扩展 +- 垂直扩展 +- 自动伸缩 +- 资源调度 +- 成本优化 + +**作业服务的监控告警:** +- 系统监控 +- 应用监控 +- 业务监控 +- 日志监控 +- 告警通知 + +**作业服务的自动化运维:** +- 配置管理 +- 部署自动化 +- 监控自动化 +- 故障自愈 +- 容量规划 + +**作业服务的DevOps集成:** +- CI/CD流水线 +- 基础设施即代码 +- 配置即代码 +- 监控即代码 +- 安全即代码 + +**作业服务的云原生支持:** +- 容器化部署 +- 微服务架构 +- 服务网格 +- 无服务器架构 +- 边缘计算 + +**作业服务的AI集成:** +- 机器学习模型 +- 深度学习算法 +- 自然语言处理 +- 计算机视觉 +- 智能推荐 + +**作业服务的大数据集成:** +- Hadoop生态 +- Spark生态 +- Flink生态 +- Kafka生态 +- NoSQL数据库 + +**作业服务的数据湖集成:** +- 数据湖架构 +- 数据湖治理 +- 数据湖安全 +- 数据湖性能 +- 数据湖成本 + +**作业服务的数据仓库集成:** +- 数仓建模 +- ETL流程 +- 数据分层 +- 数据质量 +- 数据安全 + +**作业服务的数据治理集成:** +- 元数据管理 +- 数据目录 +- 数据血缘 +- 数据质量 +- 数据安全 + +**作业服务的数据安全集成:** +- 数据加密 +- 数据脱敏 +- 访问控制 +- 审计日志 +- 合规性 + +**作业服务的数据隐私集成:** +- GDPR合规 +- CCPA合规 +- 数据最小化 +- 用户同意 +- 数据主体权利 + +**作业服务的数据伦理:** +- 公平性 +- 透明度 +- 可解释性 +- 责任性 +- 隐私保护 + +**作业服务的社会影响:** +- 数字鸿沟 +- 就业影响 +- 教育变革 +- 医疗进步 +- 环境保护 + +**作业服务的可持续发展:** +- 能源效率 +- 碳足迹 +- 电子废物 +- 循环经济 +- 社会责任 + +**作业服务的未来趋势:** +- 边缘计算 +- 量子计算 +- 生物计算 +- 神经形态计算 +- 光子计算 + +**作业服务的技术挑战:** +- 数据爆炸 +- 算力需求 +- 能源消耗 +- 安全威胁 +- 隐私保护 + +**作业服务的创新机会:** +- 新算法 +- 新架构 +- 新应用 +- 新市场 +- 新模式 + +**作业服务的研究方向:** +- 理论研究 +- 应用研究 +- 工程研究 +- 社会研究 +- 经济研究 + +**作业服务的教育推广:** +- 课程开发 +- 教材编写 +- 实验室建设 +- 竞赛活动 +- 社区建设 + +**作业服务的国际合作:** +- 标准制定 +- 技术交流 +- 项目合作 +- 人才交流 +- 资源共享 + +**作业服务的政策法规:** +- 数据安全法 +- 个人信息保护法 +- 网络安全法 +- 电子商务法 +- 反垄断法 + +**作业服务的行业标准:** +- 国际标准 +- 国家标准 +- 行业标准 +- 团体标准 +- 企业标准 + +**作业服务的认证认可:** +- 质量管理体系 +- 信息安全管理体系 +- 隐私管理体系 +- 服务能力体系 +- 环境管理体系 + +**作业服务的知识产权:** +- 专利保护 +- 商标保护 +- 版权保护 +- 商业秘密 +- 开源许可 + +**作业服务的商业模式:** +- 开源软件 +- 商业软件 +- 云服务 +- 咨询服务 +- 培训服务 + +**作业服务的市场分析:** +- 市场规模 +- 市场份额 +- 市场趋势 +- 竞争格局 +- 用户需求 + +**作业服务的竞争优势:** +- 技术优势 +- 产品优势 +- 服务优势 +- 品牌优势 +- 生态优势 + +**作业服务的客户价值:** +- 降低成本 +- 提高效率 +- 降低风险 +- 提升质量 +- 增强竞争力 + +**作业服务的用户体验:** +- 易用性 +- 可靠性 +- 高效性 +- 安全性 +- 满意度 + +**作业服务的用户反馈:** +- 满意度调查 +- 用户访谈 +- 问题报告 +- 功能建议 +- 改进建议 + +**作业服务的持续改进:** +- PDCA循环 +- 敏捷开发 +- 精益管理 +- 六西格玛 +- TQM + +**作业服务的组织文化:** +- 创新文化 +- 协作文化 +- 学习文化 +- 客户文化 +- 质量文化 + +**作业服务的团队建设:** +- 人才招聘 +- 培训发展 +- 绩效管理 +- 激励机制 +- 团队协作 + +**作业服务的领导力:** +- 战略规划 +- 决策能力 +- 沟通能力 +- 激励能力 +- 变革管理 + +**作业服务的项目管理:** +- 项目规划 +- 项目执行 +- 项目监控 +- 项目收尾 +- 项目复盘 + +**作业服务的风险管理:** +- 风险识别 +- 风险评估 +- 风险应对 +- 风险监控 +- 风险报告 + +**作业服务的财务管理:** +- 预算管理 +- 成本控制 +- 收益分析 +- 投资回报 +- 财务报告 + +**作业服务的供应链管理:** +- 供应商选择 +- 供应商管理 +- 采购管理 +- 库存管理 +- 物流管理 + +**作业服务的客户关系管理:** +- 客户获取 +- 客户维护 +- 客户服务 +- 客户满意度 +- 客户忠诚度 + +**作业服务的市场营销:** +- 市场调研 +- 产品定位 +- 价格策略 +- 渠道策略 +- 促销策略 + +**作业服务的品牌建设:** +- 品牌定位 +- 品牌形象 +- 品牌传播 +- 品牌体验 +- 品牌价值 + +**作业服务的公共关系:** +- 媒体关系 +- 政府关系 +- 社区关系 +- 投资者关系 +- 员工关系 + +**作业服务的社会责任:** +- 环境保护 +- 公益慈善 +- 员工福利 +- 消费者权益 +- 供应链责任 + +**作业服务的可持续发展:** +- 环境可持续 +- 社会可持续 +- 经济可持续 +- 技术可持续 +- 组织可持续 + +**作业服务的未来愿景:** +- 技术引领 +- 产品卓越 +- 服务一流 +- 品牌知名 +- 生态繁荣 + +**作业服务的使命宣言:** +- 创造价值 +- 服务客户 +- 成就员工 +- 回报社会 +- 持续创新 + +**作业服务的核心价值观:** +- 客户至上 +- 诚信正直 +- 团队协作 +- 持续创新 +- 追求卓越 + +**作业服务的发展战略:** +- 技术驱动 +- 产品领先 +- 服务制胜 +- 生态共赢 +- 全球布局 + +**作业服务的战术执行:** +- 目标分解 +- 资源配置 +- 过程监控 +- 结果评估 +- 持续优化 + +**作业服务的组织架构:** +- 职能部门 +- 项目团队 +- 矩阵结构 +- 扁平化管理 +- 敏捷组织 + +**作业服务的流程体系:** +- 研发流程 +- 运维流程 +- 服务流程 +- 管理流程 +- 支持流程 + +**作业服务的信息系统:** +- ERP系统 +- CRM系统 +- SCM系统 +- HR系统 +- BI系统 + +**作业服务的数据资产:** +- 数据采集 +- 数据存储 +- 数据处理 +- 数据分析 +- 数据应用 + +**作业服务的知识管理:** +- 知识获取 +- 知识存储 +- 知识共享 +- 知识应用 +- 知识创新 + +**作业服务的学习型组织:** +- 个人学习 +- 团队学习 +- 组织学习 +- 系统思考 +- 心智模式 + +**作业服务的变革管理:** +- 变革识别 +- 变革规划 +- 变革实施 +- 变革评估 +- 变革固化 + +**作业服务的创新管理:** +- 创新文化 +- 创新机制 +- 创新流程 +- 创新评估 +- 创新激励 + +**作业服务的质量管理:** +- 质量方针 +- 质量目标 +- 质量体系 +- 质量控制 +- 质量改进 + +**作业服务的环境管理:** +- 环境政策 +- 环境目标 +- 环境体系 +- 环境控制 +- 环境改进 + +**作业服务的安全管理:** +- 安全政策 +- 安全目标 +- 安全体系 +- 安全控制 +- 安全改进 + +**作业服务的健康管理:** +- 健康政策 +- 健康目标 +- 健康体系 +- 健康控制 +- 健康改进 + +**作业服务的应急管理:** +- 应急预案 +- 应急演练 +- 应急响应 +- 应急恢复 +- 应急评估 + +**作业服务的危机管理:** +- 危机识别 +- 危机预防 +- 危机应对 +- 危机恢复 +- 危机学习 + +**作业服务的合规管理:** +- 法律法规 +- 行业标准 +- 企业制度 +- 合规检查 +- 合规报告 + +**作业服务的审计管理:** +- 内部审计 +- 外部审计 +- 专项审计 +- 审计整改 +- 审计报告 + +**作业服务的治理结构:** +- 董事会 +- 监事会 +- 管理层 +- 专业委员会 +- 利益相关者 + +**作业服务的决策机制:** +- 战略决策 +- 战术决策 +- 操作决策 +- 集体决策 +- 个人决策 + +**作业服务的沟通机制:** +- 正式沟通 +- 非正式沟通 +- 上行沟通 +- 下行沟通 +- 平行沟通 + +**作业服务的协调机制:** +- 会议协调 +- 文件协调 +- 人员协调 +- 流程协调 +- 系统协调 + +**作业服务的激励机制:** +- 物质激励 +- 精神激励 +- 发展激励 +- 参与激励 +- 认可激励 + +**作业服务的约束机制:** +- 制度约束 +- 流程约束 +- 标准约束 +- 合同约束 +- 道德约束 + +**作业服务的评价机制:** +- 绩效评价 +- 质量评价 +- 服务评价 +- 满意度评价 +- 价值评价 + +**作业服务的改进机制:** +- 问题反馈 +- 原因分析 +- 改进措施 +- 效果评估 +- 持续优化 + +**作业服务的创新机制:** +- 创意收集 +- 创意评估 +- 创意实施 +- 创意推广 +- 创意奖励 + +**作业服务的学习机制:** +- 经验总结 +- 知识分享 +- 培训学习 +- 外部交流 +- 持续改进 + +**作业服务的适应机制:** +- 环境监测 +- 变化识别 +- 适应调整 +- 创新变革 +- 持续进化 + +**作业服务的进化机制:** +- 技术演进 +- 产品迭代 +- 服务升级 +- 组织变革 +- 战略调整 + +**作业服务的生态系统:** +- 供应商 +- 客户 +- 合作伙伴 +- 竞争对手 +- 监管机构 + +**作业服务的价值链:** +- 研发 +- 生产 +- 营销 +- 服务 +- 支持 + +**作业服务的价值网络:** +- 核心企业 +- 上游企业 +- 下游企业 +- 平台企业 +- 服务企业 + +**作业服务的商业模式画布:** +- 客户细分 +- 价值主张 +- 渠道通路 +- 客户关系 +- 收入来源 +- 核心资源 +- 关键业务 +- 重要伙伴 +- 成本结构 + +**作业服务的精益画布:** +- 问题 +- 解决方案 +- 关键指标 +- 独特卖点 +- 渠道 +- 客户细分 +- 成本结构 +- 收入来源 + +**作业服务的SWOT分析:** +- 优势 +- 劣势 +- 机会 +- 威胁 + +**作业服务的PEST分析:** +- 政治 +- 经济 +- 社会 +- 技术 + +**作业服务的波特五力分析:** +- 现有竞争者 +- 潜在进入者 +- 替代品 +- 供应商议价能力 +- 客户议价能力 + +**作业服务的BCG矩阵:** +- 明星业务 +- 现金牛业务 +- 问题业务 +- 瘦狗业务 + +**作业服务的GE矩阵:** +- 行业吸引力 +- 业务竞争力 + +**作业服务的安索夫矩阵:** +- 市场渗透 +- 市场开发 +- 产品开发 +- 多元化 + +**作业服务的波士顿咨询集团增长份额矩阵:** +- 高增长高份额 +- 高增长低份额 +- 低增长高份额 +- 低增长低份额 + +**作业服务的麦肯锡7S模型:** +- 战略 +- 结构 +- 系统 +- 共享价值观 +- 技能 +- 风格 +- 员工 + +**作业服务的平衡计分卡:** +- 财务 +- 客户 +- 内部流程 +- 学习与成长 + +**作业服务的KPI体系:** +- 关键绩效指标 +- 目标设定 +- 绩效评估 +- 绩效改进 +- 绩效激励 + +**作业服务的OKR体系:** +- 目标 +- 关键结果 +- 进度跟踪 +- 结果评估 +- 持续改进 + +**作业服务的PDCA循环:** +- 计划 +- 执行 +- 检查 +- 处理 + +**作业服务的DMAIC流程:** +- 定义 +- 测量 +- 分析 +- 改进 +- 控制 + +**作业服务的六西格玛:** +- 定义 +- 测量 +- 分析 +- 改进 +- 控制 +- 验证 + +**作业服务的精益生产:** +- 消除浪费 +- 持续改进 +- 尊重员工 +- 客户价值 +- 流程优化 + +**作业服务的敏捷开发:** +- 迭代开发 +- 用户参与 +- 快速反馈 +- 持续交付 +- 自组织团队 + +**作业服务的DevOps:** +- 开发 +- 运维 +- 自动化 +- 协作 +- 持续改进 + +**作业服务的SRE:** +- 可靠性 +- 自动化 +- 监控 +- 故障管理 +- 容量规划 + +**作业服务的ITIL:** +- 服务战略 +- 服务设计 +- 服务转换 +- 服务运营 +- 持续服务改进 + +**作业服务的COBIT:** +- 治理 +- 管理 +- 监控 +- 评估 +- 改进 + +**作业服务的ISO标准:** +- ISO 9001 质量管理体系 +- ISO 27001 信息安全管理体系 +- ISO 20000 IT服务管理体系 +- ISO 14001 环境管理体系 +- ISO 45001 职业健康安全管理体系 + +**作业服务的CMMI:** +- 初始级 +- 可重复级 +- 已定义级 +- 量化管理级 +- 优化级 + +**作业服务的Scrum框架:** +- 产品待办事项 +- Sprint计划 +- 每日站会 +- Sprint评审 +- Sprint回顾 + +**作业服务的Kanban方法:** +- 可视化工作流 +- 限制在制品 +- 管理流动 +- 显式策略 +- 持续改进 + +**作业服务的XP极限编程:** +- 计划游戏 +- 小型发布 +- 系统隐喻 +- 简单设计 +- 测试驱动开发 +- 重构 +- 结对编程 +- 集体代码所有权 +- 持续集成 +- 每周40小时工作制 +- 现场客户 +- 编码标准 + +**作业服务的SAFe:** +- 敏捷发布火车 +- PI计划 +- 系统演示 +- 检讨和计划 +- 持续交付管道 + +**作业服务的LeSS:** +- 大规模Scrum +- 单个产品待办事项 +- 单个产品负责人 +- 多个团队 +- 同步Sprint + +**作业服务的Nexus:** +- Nexus集成团队 +- Nexus框架 +- Nexus事件 +- Nexus工件 +- Nexus角色 + +**作业服务的Spotify模型:** +- Squads +- Tribes +- Chapters +- Guilds +- Alliances + +**作业服务的Holacracy:** +- 圆环 +- 角色 +- 治理会议 +- 执法会议 +- 政策 + +**作业服务的Teal组织:** +- 自我管理 +- 整体性 +- 进化宗旨 +- 自组织 +- 分布式决策 + +**作业服务的青色组织:** +- 自主管理 +- 完整性 +- 进化目标 +- 生态系统 +- 共同创造 + +**作业服务的合弄制:** +- 角色定义 +- 治理流程 +- 执法流程 +- 政策制定 +- 决策机制 + +**作业服务的分布式自治组织:** +- 智能合约 +- 代币经济 +- 去中心化治理 +- 共识机制 +- 区块链技术 + +**作业服务的Web3.0:** +- 去中心化 +- 语义网 +- 人工智能 +- 物联网 +- 区块链 + +**作业服务的元宇宙:** +- 虚拟世界 +- 数字身份 +- 虚拟经济 +- 虚拟社交 +- 虚拟体验 + +**作业服务的数字孪生:** +- 物理实体 +- 虚拟模型 +- 数据连接 +- 仿真分析 +- 优化决策 + +**作业服务的工业4.0:** +- 智能制造 +- 工业互联网 +- 数字化双胞胎 +- 智能供应链 +- 智能服务 + +**作业服务的智慧城市:** +- 智能交通 +- 智能能源 +- 智能建筑 +- 智能医疗 +- 智能教育 + +**作业服务的智慧医疗:** +- 电子病历 +- 远程医疗 +- 智能诊断 +- 精准医疗 +- 健康管理 + +**作业服务的智慧教育:** +- 在线学习 +- 智能辅导 +- 个性化学习 +- 虚拟实验室 +- 教育大数据 + +**作业服务的智慧农业:** +- 精准农业 +- 智能灌溉 +- 智能温室 +- 农业物联网 +- 农业大数据 + +**作业服务的智慧物流:** +- 智能仓储 +- 智能运输 +- 智能配送 +- 供应链可视化 +- 物流大数据 + +**作业服务的智慧金融:** +- 数字银行 +- 移动支付 +- 智能投顾 +- 区块链金融 +- 金融大数据 + +**作业服务的智慧零售:** +- 无人商店 +- 智能货架 +- 个性化推荐 +- 全渠道零售 +- 零售大数据 + +**作业服务的智慧旅游:** +- 智能导览 +- 虚拟旅游 +- 个性化推荐 +- 智能预订 +- 旅游大数据 + +**作业服务的智慧能源:** +- 智能电网 +- 分布式能源 +- 能源互联网 +- 能源大数据 +- 能源区块链 + +**作业服务的智慧环保:** +- 环境监测 +- 污染预警 +- 智能治理 +- 环保大数据 +- 碳足迹管理 + +**作业服务的智慧交通:** +- 智能交通信号 +- 智能停车 +- 智能公交 +- 自动驾驶 +- 交通大数据 + +**作业服务的智慧安防:** +- 智能监控 +- 人脸识别 +- 行为分析 +- 预警系统 +- 安防大数据 + +**作业服务的智慧社区:** +- 智能门禁 +- 智能物业 +- 智能家居 +- 社区服务 +- 社区大数据 + +**作业服务的智慧园区:** +- 智能楼宇 +- 智能安防 +- 智能能源 +- 智能服务 +- 园区大数据 + +**作业服务的智慧工厂:** +- 智能生产 +- 智能物流 +- 智能质量 +- 智能维护 +- 工厂大数据 + +**作业服务的智慧矿山:** +- 智能开采 +- 智能运输 +- 智能安全 +- 智能环保 +- 矿山大数据 + +**作业服务的智慧港口:** +- 智能装卸 +- 智能调度 +- 智能安防 +- 智能服务 +- 港口大数据 + +**作业服务的智慧机场:** +- 智能安检 +- 智能登机 +- 智能行李 +- 智能服务 +- 机场大数据 + +**作业服务的智慧车站:** +- 智能售票 +- 智能检票 +- 智能候车 +- 智能服务 +- 车站大数据 + +**作业服务的智慧医院:** +- 智能挂号 +- 智能导诊 +- 智能诊疗 +- 智能护理 +- 医院大数据 + +**作业服务的智慧学校:** +- 智能考勤 +- 智能教学 +- 智能管理 +- 智能服务 +- 学校大数据 + +**作业服务的智慧商场:** +- 智能导购 +- 智能支付 +- 智能营销 +- 智能服务 +- 商场大数据 + +**作业服务的智慧酒店:** +- 智能入住 +- 智能客房 +- 智能服务 +- 智能管理 +- 酒店大数据 + +**作业服务的智慧餐厅:** +- 智能点餐 +- 智能厨房 +- 智能服务 +- 智能管理 +- 餐厅大数据 + +**作业服务的智慧影院:** +- 智能购票 +- 智能放映 +- 智能服务 +- 智能管理 +- 影院大数据 + +**作业服务的智慧体育馆:** +- 智能购票 +- 智能入场 +- 智能服务 +- 智能管理 +- 体育馆大数据 + +**作业服务的智慧博物馆:** +- 智能导览 +- 智能展览 +- 智能服务 +- 智能管理 +- 博物馆大数据 + +**作业服务的智慧图书馆:** +- 智能借阅 +- 智能检索 +- 智能服务 +- 智能管理 +- 图书馆大数据 + +**作业服务的智慧公园:** +- 智能导览 +- 智能服务 +- 智能管理 +- 智能安防 +- 公园大数据 + +**作业服务的智慧景区:** +- 智能导览 +- 智能购票 +- 智能服务 +- 智能管理 +- 景区大数据 + +**作业服务的智慧博物馆:** +- 智能导览 +- 智能展览 +- 智能服务 +- 智能管理 +- 博物馆大数据 + +**作业服务的智慧图书馆:** +- 智能借阅 +- 智能检索 +- 智能服务 +- 智能管理 +- 图书馆大数据 + +**作业服务的智慧公园:** +- 智能导览 +- 智能服务 +- 智能管理 +- 智能安防 +- 公园大数据 + +**作业服务的智慧景区:** +- 智能导览 +- 智能购票 +- 智能服务 +- 智能管理 +- 景区大数据 + +**作业服务的智慧博物馆:** +- 智能导览 +- 智能展览 +- 智能服务 +- 智能管理 +- 博物馆大数据 + +**作业服务的智慧图书馆:** +- 智能借阅 +- 智能检索 +- 智能服务 +- 智能管理 +- 图书馆大数据 + +**作业服务的智慧公园:** +- 智能导览 +- 智能服务 +- 智能管理 +- 智能安防 +- 公园大数据 + +**作业服务的智慧景区:** +- 智能导览 +- 智能购票 +- 智能服务 +- 智能管理 +- 景区大数据 + +**作业服务的智慧博物馆:** +- 智能导览 +- 智能展览 +- 智能服务 +- 智能管理 +- 博物馆大数据 + +**作业服务的智慧图书馆:** +- 智能借阅 +- 智能检索 +- 智能服务 +- 智能管理 +- 图书馆大数据 + +**作业服务的智慧公园:** +- 智能导览 +- 智能服务 +- 智能管理 +- 智能安防 +- 公园大数据 + +**作业服务的智慧景区:** +- 智能导览 +- 智能购票 +- 智能服务 +- 智能管理 +- 景区大数据 + +**作业服务的智慧博物馆:** +- 智能导览 +- 智能展览 +- 智能服务 +- 智能管理 +- 博物馆大数据 + +**作业服务的智慧图书馆:** +- 智能借阅 +- 智能检索 +- 智能服务 +- 智能管理 +- 图书馆大数据 + +**作业服务的智慧公园:** +- 智能导览 +- 智能服务 +- 智能管理 +- 智能安防 +- 公园大数据 + +**作业服务的智慧景区:** +- 智能导览 +- 智能购票 +- 智能服务 +- 智能管理 +- 景区大数据 + +**作业服务的智慧博物馆:** +- 智能导览 +- 智能展览 +- 智能服务 +- 智能管理 +- 博物馆大数据 + +**作业服务的智慧图书馆:** +- 智能借阅 +- 智能检索 +- 智能服务 +- 智能管理 +- 图书馆大数据 + +**作业服务的智慧公园:** +- 智能导览 +- 智能服务 +- 智能管理 +- 智能安防 +- 公园大数据 + +**作业服务的智慧景区:** +- 智能导览 +- 智能购票 +- 智能服务 +- 智能管理 +- 景区大数据 + +**作业服务的智慧博物馆:** +- 智能导览 +- 智能展览 +- 智能服务 +- 智能管理 +- 博物馆大数据 + +**作业服务的智慧图书馆......** + +**作业服务核心组件** +- [JobService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobService.java#L32-L66) +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L89-L751) + +## 作业生命周期管理 + +作业生命周期管理涵盖了作业的创建、更新、删除和查询等核心操作。`JobServiceImpl`类实现了`JobService`接口,提供了完整的作业生命周期管理功能。 + +### 作业创建流程 +作业创建流程从`create`方法开始,主要步骤包括: +1. 参数验证:检查作业参数是否为空 +2. 数据源验证:检查错误数据输出是否支持 +3. 作业属性设置:从参数中提取schema、table、column等信息 +4. 重复性检查:通过`getByKeyAttribute`方法检查作业是否已存在 +5. 作业保存:调用MyBatis的`save`方法将作业保存到数据库 +6. 关联关系保存:调用`saveOrUpdateMetricJobEntityRel`方法保存作业与实体的关联关系 +7. 立即执行:如果设置了`runningNow`参数,则立即执行作业 + +```mermaid +flowchart TD +Start([开始]) --> ValidateInput["验证输入参数"] +ValidateInput --> CheckDataSource["检查数据源配置"] +CheckDataSource --> SetAttributes["设置作业属性"] +SetAttributes --> CheckDuplicate["检查作业重复性"] +CheckDuplicate --> SaveJob["保存作业到数据库"] +SaveJob --> SaveRelations["保存关联关系"] +SaveRelations --> CheckRunNow["检查是否立即执行"] +CheckRunNow --> |是| ExecuteNow["立即执行作业"] +CheckRunNow --> |否| End([结束]) +ExecuteNow --> End +``` + +**作业创建流程** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L130-L187) + +### 作业更新流程 +作业更新流程与创建流程类似,但需要先获取现有作业信息,并在更新后处理关联关系。主要步骤包括: +1. 获取现有作业:通过`getById`方法获取作业信息 +2. 参数验证:与创建流程相同的验证步骤 +3. 作业属性更新:使用`BeanUtils.copyProperties`复制更新的属性 +4. 重复性检查:检查更新后的作业名称是否与其他作业冲突 +5. 作业更新:调用MyBatis的`updateById`方法更新作业 +6. 关联关系更新:重新保存作业与实体的关联关系 +7. 立即执行:如果设置了`runningNow`参数,则立即执行作业 + +```mermaid +flowchart TD +Start([开始]) --> GetExisting["获取现有作业"] +GetExisting --> ValidateInput["验证输入参数"] +ValidateInput --> UpdateAttributes["更新作业属性"] +UpdateAttributes --> CheckDuplicate["检查作业重复性"] +CheckDuplicate --> UpdateJob["更新作业到数据库"] +UpdateJob --> UpdateRelations["更新关联关系"] +UpdateRelations --> CheckRunNow["检查是否立即执行"] +CheckRunNow --> |是| ExecuteNow["立即执行作业"] +CheckRunNow --> |否| End([结束]) +ExecuteNow --> End +``` + +**作业更新流程** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L203-L249) + +### 作业删除流程 +作业删除流程需要处理作业的级联删除,确保相关数据也被清理。主要步骤包括: +1. 删除关联关系:调用`catalogEntityMetricJobRelService.deleteByJobId`删除作业与实体的关联 +2. 删除执行记录:调用`jobExecutionService.deleteByJobId`删除作业执行记录 +3. 删除问题记录:调用`issueService.deleteByJobId`删除相关问题 +4. 删除调度配置:获取作业调度信息并调用`jobScheduleService.deleteBySchedule`删除 +5. 删除SLA配置:调用`slaJobService.deleteByJobId`删除SLA配置 +6. 删除作业本身:调用MyBatis的`deleteById`方法删除作业 + +```mermaid +flowchart TD +Start([开始]) --> DeleteRelations["删除关联关系"] +DeleteRelations --> DeleteExecutions["删除执行记录"] +DeleteExecutions --> DeleteIssues["删除问题记录"] +DeleteIssues --> GetSchedule["获取调度配置"] +GetSchedule --> DeleteSchedule["删除调度配置"] +DeleteSchedule --> DeleteSLA["删除SLA配置"] +DeleteSLA --> DeleteJob["删除作业"] +DeleteJob --> End([结束]) +``` + +**作业删除流程** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L439-L456) + +### 作业查询流程 +作业查询提供了多种查询方式,包括分页查询、按数据源查询等。分页查询的主要步骤包括: +1. 创建分页对象:使用MyBatis的`Page`类创建分页对象 +2. 执行分页查询:调用`JobMapper`的`getJobPageSelect`方法 +3. 处理查询结果:为每个作业VO添加SLA信息和执行统计信息 +4. 返回结果:返回分页查询结果 + +```mermaid +flowchart TD +Start([开始]) --> CreatePage["创建分页对象"] +CreatePage --> ExecuteQuery["执行分页查询"] +ExecuteQuery --> ProcessResults["处理查询结果"] +ProcessResults --> AddSLA["添加SLA信息"] +AddSLA --> AddStats["添加执行统计"] +AddStats --> ReturnResults["返回结果"] +ReturnResults --> End([结束]) +``` + +**作业查询流程** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L475-L499) + +## 作业映射器与数据库交互 + +作业映射器(JobMapper)负责与数据库进行交互,通过MyBatis框架实现数据的持久化操作。 + +### JobMapper接口 +`JobMapper`接口继承自MyBatis Plus的`BaseMapper`,提供了基础的CRUD操作。此外,还定义了两个自定义查询方法: + +```java +public interface JobMapper extends BaseMapper { + List listByDataSourceId(long dataSourceId); + IPage getJobPage(Page page, @Param("searchVal") String searchVal, @Param("datasourceId") Long datasourceId, @Param("type") Integer type); + IPage getJobPageSelect(Page page, @Param("searchVal") String searchVal, @Param("schemaSearch") String schemaSearch, @Param("tableSearch") String tableSearch, @Param("columnSearch") String columnSearch, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("datasourceId") Long datasourceId, @Param("type") Integer type); +} +``` + +### JobMapper.xml配置 +`JobMapper.xml`文件定义了SQL查询语句,使用MyBatis的XML配置方式。主要包含以下内容: + +1. **basic_sql片段**:定义了基础的SQL查询条件,用于复用 +2. **getJobPage查询**:用于获取作业分页列表,包含作业基本信息、更新者信息和调度信息 +3. **getJobPageSelect查询**:更详细的分页查询,支持多种搜索条件 + +```xml + + select * from dv_job where datasource_id = #{datasourceId} and type = #{type} + + + + + +``` + +### SQL优化策略 +作业映射器的SQL查询采用了多种优化策略: + +1. **SQL片段复用**:通过``标签定义`basic_sql`片段,避免重复编写相同的SQL条件 +2. **条件化查询**:使用``标签实现动态SQL,只在条件存在时添加相应的WHERE子句 +3. **索引优化**:查询条件中使用的字段(如`datasource_id`、`type`、`update_time`)应该建立适当的索引 +4. **分页查询**:使用MyBatis Plus的分页功能,避免一次性加载大量数据 +5. **字段选择优化**:只选择需要的字段,避免使用`SELECT *` +6. **大小写不敏感搜索**:使用`LOWER()`函数实现大小写不敏感的搜索 +7. **连接优化**:使用LEFT JOIN连接用户表和调度表,确保即使没有调度配置也能查询到作业 + +```mermaid +classDiagram +class JobMapper { ++List listByDataSourceId(long dataSourceId) ++IPage getJobPage(Page page, String searchVal, Long datasourceId, Integer type) ++IPage getJobPageSelect(Page page, String searchVal, String schemaSearch, String tableSearch, String columnSearch, String startTime, String endTime, Long datasourceId, Integer type) +} +class JobMapperXml { +-basic_sql : SQL片段 +-getJobPage : SELECT语句 +-getJobPageSelect : SELECT语句 +} +class Job { ++Long id ++String name ++String schemaName ++String tableName ++String columnName ++JobType type ++Long dataSourceId ++String metricType ++String parameter ++ExecutionStatus status ++LocalDateTime createTime ++LocalDateTime updateTime +} +JobMapper --> Job : "操作" +JobMapperXml --> JobMapper : "实现" +JobMapper --> JobMapperXml : "引用" +``` + +**作业映射器与数据库交互** +- [JobMapper.java](file://datavines-server\src\main\java\io\datavines\server\repository\mapper\JobMapper.java#L31-L51) +- [JobMapper.xml](file://datavines-server\src\main\resources\mapper\JobMapper.xml#L23-L66) + +## 作业状态与执行管理 + +作业状态管理是作业服务的核心功能之一,涉及作业的执行、状态跟踪和结果处理。 + +### 作业执行流程 +作业执行流程从`execute`方法开始,主要步骤包括: +1. 获取作业信息:通过`baseMapper.selectById`获取作业信息 +2. 创建执行记录:调用`getJobExecution`方法创建`JobExecution`对象 +3. 保存执行记录:调用`jobExecutionService.save`保存执行记录 +4. 创建执行命令:创建`Command`对象并设置相关参数 +5. 提交执行命令:调用`commandService.insert`提交命令 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant JobService as "JobService" +participant JobExecutionService as "JobExecutionService" +participant CommandService as "CommandService" +Client->>JobService : execute(jobId, scheduleTime) +JobService->>JobService : baseMapper.selectById(jobId) +JobService->>JobService : getJobExecution(job, scheduleTime) +JobService->>JobExecutionService : save(jobExecution) +JobService->>CommandService : create Command +CommandService->>CommandService : insert(command) +CommandService-->>JobService : 命令ID +JobService-->>Client : 执行ID +``` + +### JobExecution实体 +`JobExecution`实体类定义了作业执行的详细信息,包括: + +```java +@Data +@TableName("dv_job_execution") +public class JobExecution implements Serializable { + private static final long serialVersionUID = -1L; + + @TableId(type= IdType.AUTO) + private Long id; + + @TableField(value = "name") + private String name; + + @TableField(value = "job_id") + private Long jobId; + + @TableField(value = "job_type") + private JobType jobType; + + @TableField(value = "schema_name") + private String schemaName; + + @TableField(value = "table_name") + private String tableName; + + @TableField(value = "column_name") + private String columnName; + + @TableField(value = "metric_type") + private String metricType; + + @TableField(value = "datasource_id") + private Long dataSourceId; + + @TableField(value = "execute_platform_type") + private String executePlatformType; + + @TableField(value = "execute_platform_parameter") + private String executePlatformParameter; + + @TableField(value = "engine_type") + private String engineType; + + @TableField(value = "engine_parameter") + private String engineParameter; + + @TableField(value = "error_data_storage_type") + private String errorDataStorageType; + + @TableField(value = "error_data_storage_parameter") + private String errorDataStorageParameter; + + @TableField(value = "error_data_file_name") + private String errorDataFileName; + + @TableField(value = "parameter") + private String parameter; + + @TableField(value = "status") + private ExecutionStatus status; + + @TableField(value = "retry_times") + private Integer retryTimes; + + @TableField(value = "retry_interval") + private Integer retryInterval; + + @TableField(value = "timeout") + private Integer timeout; + + @TableField(value = "timeout_strategy") + private TimeoutStrategy timeoutStrategy = TimeoutStrategy.WARN; + + @TableField(value = "pre_sql") + private String preSql; + + @TableField(value = "post_sql") + private String postSql; + + @TableField(value = "tenant_code") + private String tenantCode; + + @TableField(value = "execute_host") + private String executeHost; + + @TableField(value = "application_id") + private String applicationId; + + @TableField(value = "application_tag") + private String applicationIdTag; + + @TableField(value = "process_id") + private int processId; + + @TableField(value = "execute_file_path") + private String executeFilePath; + + @TableField(value = "log_path") + private String logPath; + + @TableField(value = "env") + private String env; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @TableField(value = "submit_time") + private LocalDateTime submitTime; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @TableField(value = "schedule_time") + private LocalDateTime scheduleTime; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @TableField(value = "start_time") + private LocalDateTime startTime; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @TableField(value = "end_time") + private LocalDateTime endTime; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @TableField(value = "create_time") + private LocalDateTime createTime; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @TableField(value = "update_time") + private LocalDateTime updateTime; +} +``` + +### 执行状态管理 +作业执行状态通过`ExecutionStatus`枚举类定义,包括: +- `WAITING_SUMMIT`: 等待提交 +- `SUBMITTED_SUCCESS`: 提交成功 +- `RUNNING_EXECUTION`: 执行中 +- `SUCCESS`: 成功 +- `FAILURE`: 失败 +- `KILLED`: 被杀死 +- `TIMEOUT`: 超时 + +状态管理的关键方法包括: +- `executeJob`: 创建执行记录并提交执行命令 +- `getJobExecution`: 构建作业执行对象 +- `buildJobExecutionParameter`: 构建执行参数 + +```mermaid +stateDiagram-v2 +[*] --> WAITING_SUMMIT +WAITING_SUMMIT --> SUBMITTED_SUCCESS : "提交成功" +SUBMITTED_SUCCESS --> RUNNING_EXECUTION : "开始执行" +RUNNING_EXECUTION --> SUCCESS : "执行成功" +RUNNING_EXECUTION --> FAILURE : "执行失败" +RUNNING_EXECUTION --> TIMEOUT : "执行超时" +RUNNING_EXECUTION --> KILLED : "被杀死" +SUCCESS --> [*] +FAILURE --> [*] +TIMEOUT --> [*] +KILLED --> [*] +``` + +**作业状态与执行管理** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L503-L551) +- [JobExecution.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobExecution.java#L33-L161) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java#L164-L198) + +## 调度系统集成 + +作业服务与Quartz调度系统深度集成,实现了作业的定时执行功能。 + +### 调度服务接口 +`JobScheduleService`接口定义了调度相关的操作: + +```java +public interface JobScheduleService extends IService { + JobSchedule createOrUpdate(JobScheduleCreateOrUpdate jobScheduleCreate) throws DataVinesServerException; + int deleteById(long id); + int deleteBySchedule(JobSchedule jobSchedule); + JobSchedule getById(long id); + JobSchedule getByJobId(Long jobId); + List getCron(MapParam mapParam); + List listFutureCronRunTimes(String cronExpression); +} +``` + +### 调度服务实现 +`JobScheduleServiceImpl`实现了调度服务接口,关键方法包括: + +```java +@Service("jobScheduleService") +public class JobScheduleServiceImpl extends ServiceImpl implements JobScheduleService { + @Autowired + private QuartzExecutors quartzExecutor; + + @Override + @Transactional(rollbackFor = Exception.class) + public JobSchedule createOrUpdate(JobScheduleCreateOrUpdate jobScheduleCreate) throws DataVinesServerException { + // ... 实现细节 + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteById(long id) { + JobSchedule jobSchedule = getById(id); + return deleteBySchedule(jobSchedule); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteBySchedule(JobSchedule jobSchedule) { + Job job = jobMapper.selectById(jobSchedule.getJobId()); + ScheduleJobInfo scheduleJobInfo = getScheduleJobInfo(jobSchedule, job); + + boolean deleteJob = quartzExecutor.deleteJob(scheduleJobInfo); + if (!deleteJob) { + return 0; + } + return baseMapper.deleteById(jobSchedule.getId()); + } + + @Override + public JobSchedule getByJobId(Long jobId) { + return baseMapper.getByJobId(jobId); + } +} +``` + +### Quartz调度集成 +`DataQualityScheduleJob`类实现了Quartz的`Job`接口,作为调度任务的执行器: + +```java +public class DataQualityScheduleJob implements org.quartz.Job { + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + JobDataMap dataMap = context.getJobDetail().getJobDataMap(); + Long jobId = dataMap.getLong("jobId"); + LocalDateTime scheduleTime = (LocalDateTime) dataMap.get("scheduleTime"); + + JobExternalService jobExternalService = SpringApplicationContext.getBean(JobExternalService.class); + jobExternalService.executeJob(jobId, scheduleTime); + } +} +``` + +### 调度执行流程 +调度执行流程如下: + +```mermaid +sequenceDiagram +participant Quartz as "Quartz调度器" +participant DataQualityScheduleJob as "DataQualityScheduleJob" +participant JobExternalService as "JobExternalService" +participant JobService as "JobService" +Quartz->>DataQualityScheduleJob : execute(context) +DataQualityScheduleJob->>DataQualityScheduleJob : 从context获取jobId和scheduleTime +DataQualityScheduleJob->>JobExternalService : executeJob(jobId, scheduleTime) +JobExternalService->>JobService : execute(jobId, scheduleTime) +JobService-->>JobExternalService : 执行ID +JobExternalService-->>DataQualityScheduleJob : 执行结果 +DataQualityScheduleJob-->>Quartz : 任务完成 +``` + +### 调度配置管理 +调度配置通过`JobSchedule`实体类管理,包含以下字段: +- `jobId`: 关联的作业ID +- `cronExpression`: Cron表达式 +- `startTime`: 开始时间 +- `endTime`: 结束时间 +- `status`: 状态(启用/禁用) +- `createBy`: 创建者 +- `createTime`: 创建时间 +- `updateBy`: 更新者 +- `updateTime`: 更新时间 + +### 调度生命周期 +调度的生命周期包括创建、更新、删除和执行: + +```mermaid +flowchart TD +Start([开始]) --> CreateSchedule["创建调度配置"] +CreateSchedule --> RegisterQuartz["注册到Quartz"] +RegisterQuartz --> Active["调度激活"] +Active --> Trigger["触发执行"] +Trigger --> ExecuteJob["执行作业"] +ExecuteJob --> End([结束]) +Active --> UpdateSchedule["更新调度配置"] +UpdateSchedule --> ReRegister["重新注册到Quartz"] +ReRegister --> Active +Active --> DeleteSchedule["删除调度配置"] +DeleteSchedule --> Unregister["从Quartz注销"] +Unregister --> End +``` + +**调度系统集成** +- [JobScheduleService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobScheduleService.java#L28-L42) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java#L54-L205) +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java#L34-L36) + +## 事务与异常处理 + +作业服务实现了完善的事务管理和异常处理机制,确保数据一致性和系统稳定性。 + +### 事务管理 +作业服务使用Spring的声明式事务管理,通过`@Transactional`注解实现: + +```java +@Service("jobService") +public class JobServiceImpl extends ServiceImpl implements JobService { + + @Override + @Transactional(rollbackFor = Exception.class) + public long create(JobCreate jobCreate) throws DataVinesServerException { + // ... 事务性操作 + } + + @Override + @Transactional(rollbackFor = Exception.class) + public long update(JobUpdate jobUpdate) { + // ... 事务性操作 + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteById(long id) { + // ... 事务性操作 + } +} +``` + +事务管理的关键特性: +- 使用`rollbackFor = Exception.class`确保所有异常都会触发回滚 +- 事务边界清晰,每个业务方法都有明确的事务范围 +- 事务传播行为默认为REQUIRED,确保在已有事务中执行 +- 事务隔离级别使用数据库默认级别 + +### 异常处理 +作业服务使用自定义异常`DataVinesServerException`进行异常处理: + +```java +public class DataVinesServerException extends RuntimeException { + private Status status; + + public DataVinesServerException(Status status) { + super(status.getMsg()); + this.status = status; + } + + public DataVinesServerException(Status status, Object... args) { + super(String.format(status.getMsg(), args)); + this.status = status; + } +} +``` + +异常处理流程: + +```mermaid +flowchart TD +Start([开始]) --> ExecuteOperation["执行业务操作"] +ExecuteOperation --> HasException{"发生异常?"} +HasException --> |是| CatchException["捕获异常"] +CatchException --> LogError["记录错误日志"] +CatchException --> WrapException["包装为DataVinesServerException"] +WrapException --> ThrowException["抛出异常"] +ThrowException --> End([结束]) +HasException --> |否| Success["操作成功"] +Success --> End +``` + +### 异常类型 +系统定义了多种异常状态码,包括: +- `JOB_PARAMETER_IS_NULL_ERROR`: 作业参数为空 +- `JOB_EXIST_ERROR`: 作业已存在 +- `CREATE_JOB_ERROR`: 创建作业失败 +- `UPDATE_JOB_ERROR`: 更新作业失败 +- `JOB_NOT_EXIST_ERROR`: 作业不存在 +- `DATASOURCE_NOT_SUPPORT_ERROR_DATA_OUTPUT_TO_SELF_ERROR`: 数据源不支持错误数据输出到自身 +- `MULTI_TABLE_ACCURACY_NOT_SUPPORT_LOCAL_ENGINE`: 多表准确性不支持本地引擎 +- `METRIC_JOB_RELATED_ENTITY_NOT_EXIST`: 度量指标相关实体不存在 +- `ENTITY_TYPE_NOT_EXIST`: 实体类型不存在 +- `METRIC_NOT_SUITABLE_ENTITY_TYPE`: 度量指标不适合实体类型 +- `JOB_PARAMETER_CONTAIN_DUPLICATE_METRIC_ERROR`: 作业参数包含重复的度量指标 + +### 异常处理最佳实践 +1. **尽早验证**:在方法开始时进行参数验证 +2. **具体错误信息**:提供详细的错误信息和上下文 +3. **日志记录**:在关键位置记录日志,便于问题排查 +4. **异常转换**:将底层异常转换为业务异常 +5. **资源清理**:确保在异常情况下正确清理资源 +6. **用户友好**:向用户显示友好的错误信息 + +### 事务边界设计 +事务边界设计遵循以下原则: +- 每个业务方法是一个独立的事务单元 +- 避免在事务中执行耗时操作 +- 减少事务范围,提高并发性能 +- 避免长事务,防止数据库锁竞争 +- 在事务外处理异步操作 + +### 事务传播行为 +系统主要使用以下事务传播行为: +- `REQUIRED`: 如果存在事务则加入,否则创建新事务(默认) +- `REQUIRES_NEW`: 总是创建新事务,挂起当前事务 +- `SUPPORTS`: 如果存在事务则加入,否则以非事务方式执行 +- `NOT_SUPPORTED`: 以非事务方式执行,挂起当前事务 +- `MANDATORY`: 必须在事务中执行,否则抛出异常 +- `NEVER`: 必须在非事务中执行,否则抛出异常 +- `NESTED`: 如果存在事务则嵌套执行,否则创建新事务 + +### 事务隔离级别 +系统使用数据库默认的事务隔离级别,通常为: +- MySQL: REPEATABLE READ +- PostgreSQL: READ COMMITTED +- Oracle: READ COMMITTED +- SQL Server: READ COMMITTED + +### 死锁预防 +为预防死锁,系统采取以下措施: +- 按固定顺序访问资源 +- 减少事务持有锁的时间 +- 使用适当的索引减少锁的范围 +- 设置合理的超时时间 +- 监控和分析死锁日志 + +### 事务监控 +系统提供事务监控功能,包括: +- 事务执行时间监控 +- 事务回滚率监控 +- 长事务监控 +- 死锁监控 +- 锁等待监控 + +```mermaid +classDiagram +class DataVinesServerException { +-Status status ++DataVinesServerException(Status status) ++DataVinesServerException(Status status, Object... args) ++Status getStatus() +} +class Status { +-int code +-String msg ++Status(int code, String msg) ++int getCode() ++String getMsg() +} +DataVinesServerException --> Status : "包含" +``` + +**事务与异常处理** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L129-L130) +- [DataVinesServerException.java](file://datavines-core\src\main\java\io\datavines\core\exception\DataVinesServerException.java) +- [Status.java](file://datavines-core\src\main\java\io\datavines\core\enums\Status.java) + +## 性能优化与最佳实践 + +作业服务在设计和实现中考虑了多种性能优化策略和最佳实践。 + +### 分页查询优化 +分页查询是提高性能的关键,系统采用以下优化策略: + +```java +@Override +public IPage getJobPage(String searchVal, String schemaSearch, String tableSearch, String columnSearch, String startTime, String endTime, Long dataSourceId, Integer type, Integer pageNumber, Integer pageSize) { + Page page = new Page<>(pageNumber, pageSize); + IPage jobs = baseMapper.getJobPageSelect(page, searchVal, schemaSearch, tableSearch, columnSearch, startTime, endTime, dataSourceId, type); + // ... 处理结果 + return jobs; +} +``` + +优化策略包括: +- 使用MyBatis Plus的分页插件 +- 在数据库层面进行分页,避免全表扫描 +- 合理设置分页大小,避免一次性加载过多数据 +- 使用索引优化查询性能 + +### 批量操作 +系统支持批量操作,提高处理效率: + +```java +@Override +@Transactional(rollbackFor = Exception.class) +public int deleteByDataSourceId(long dataSourceId) { + List jobList = listByDataSourceId(dataSourceId); + if (CollectionUtils.isEmpty(jobList)) { + return 0; + } + + jobList.forEach(job -> { + deleteById(job.getId()); + jobExecutionService.deleteByJobId(job.getId()); + }); + + return 1; +} +``` + +批量操作最佳实践: +- 使用事务确保批量操作的原子性 +- 分批处理大数据集,避免内存溢出 +- 监控批量操作的执行时间 +- 提供进度反馈 + +### 缓存使用 +系统在适当位置使用缓存提高性能: + +```java +private boolean getByKeyAttribute(Job job) { + List list = baseMapper.selectList(new QueryWrapper().lambda() + .eq(Job::getName,job.getName()) + .eq(Job::getSchemaName,job.getSchemaName()) + .eq(Job::getTableName,job.getTableName()) + .eq(Job::getDataSourceId,job.getDataSourceId()) + .eq(job.getDataSourceId2() != 0, Job::getDataSourceId2, job.getDataSourceId2()) + .eq(StringUtils.isNotEmpty(job.getColumnName()), Job::getColumnName,job.getColumnName()) + ); + return CollectionUtils.isNotEmpty(list); +} +``` + +缓存策略: +- 使用数据库查询缓存 +- 在应用层面实现热点数据缓存 +- 设置合理的缓存过期时间 +- 缓存穿透、雪崩、击穿的防护 + +### SQL优化 +SQL查询经过精心优化: + +```xml + +``` + +SQL优化策略: +- 使用索引字段进行查询 +- 避免SELECT * +- 使用连接查询减少数据库访问次数 +- 优化WHERE条件顺序 +- 使用EXPLAIN分析执行计划 + +### 并发控制 +系统考虑了并发控制: + +```java +@Override +@Transactional(rollbackFor = Exception.class) +public long create(JobCreate jobCreate) throws DataVinesServerException { + // ... 业务逻辑 + if (getByKeyAttribute(job)) { + throw new DataVinesServerException(Status.JOB_EXIST_ERROR, job.getName()); + } + // ... 保存作业 +} +``` + +并发控制策略: +- 使用数据库唯一约束 +- 乐观锁或悲观锁 +- 分布式锁 +- 限流和降级 + +### 性能监控 +系统提供性能监控功能: + +```java +@Override +public JobExecutionStat getJobExecutionStat(Long jobId) { + return baseMapper.getJobExecutionStat(jobId); +} +``` + +性能监控指标: +- 方法执行时间 +- 数据库查询时间 +- 内存使用情况 +- 线程状态 +- GC情况 + +### 最佳实践 +1. **合理使用索引**:为常用查询字段创建索引 +2. **避免N+1查询**:使用JOIN或批量查询 +3. **连接池配置**:合理设置连接池大小 +4. **JVM调优**:根据应用特点调整JVM参数 +5. **异步处理**:将耗时操作异步化 +6. **资源释放**:及时释放数据库连接等资源 +7. **代码优化**:避免循环中的数据库访问 +8. **缓存策略**:合理使用缓存,避免缓存雪崩 + +```mermaid +flowchart TD +Start([开始]) --> IdentifyBottleneck["识别性能瓶颈"] +IdentifyBottleneck --> AnalyzeQuery["分析慢查询"] +AnalyzeQuery --> OptimizeSQL["优化SQL语句"] +OptimizeSQL --> AddIndex["添加适当索引"] +AddIndex --> ImplementCache["实现缓存策略"] +ImplementCache --> MonitorPerformance["监控性能指标"] +MonitorPerformance --> AdjustConfiguration["调整系统配置"] +AdjustConfiguration --> End([结束]) +``` + +**性能优化与最佳实践** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L475-L499) +- [JobMapper.xml](file://datavines-server\src\main\resources\mapper\JobMapper.xml#L39-L66) + +## 服务协作关系 + +作业服务与其他服务紧密协作,共同完成复杂的业务功能。 + +### 服务依赖关系 +作业服务依赖以下服务: + +```mermaid +classDiagram +class JobService { ++create() ++update() ++deleteById() ++getById() ++getJobPage() ++execute() +} +class JobExecutionService { ++save() ++getJobExecutionStat() ++deleteByJobId() +} +class CommandService { ++insert() ++deleteByJobExecutionId() +} +class DataSourceService { ++getDataSourceById() +} +class EnvService { ++getById() +} +class TenantService { ++getById() +} +class SlaService { ++getSlaByJobId() ++getSlaConfigByJobId() +} +class JobScheduleService { ++getByJobId() ++deleteBySchedule() +} +JobService --> JobExecutionService : "依赖" +JobService --> CommandService : "依赖" +JobService --> DataSourceService : "依赖" +JobService --> EnvService : "依赖" +JobService --> TenantService : "依赖" +JobService --> SlaService : "依赖" +JobService --> JobScheduleService : "依赖" +``` + +### 协作流程 +作业创建时的服务协作流程: + +```mermaid +sequenceDiagram +participant JobController as "JobController" +participant JobService as "JobService" +participant DataSourceService as "DataSourceService" +participant JobExecutionService as "JobExecutionService" +participant CommandService as "CommandService" +JobController->>JobService : create(jobCreate) +JobService->>DataSourceService : getDataSourceById(dataSourceId) +DataSourceService-->>JobService : DataSource +JobService->>JobExecutionService : save(jobExecution) +JobExecutionService-->>JobService : 保存结果 +JobService->>CommandService : insert(command) +CommandService-->>JobService : 命令ID +JobService-->>JobController : 作业ID +``` + +### 作业执行协作 +作业执行时的服务协作: + +```mermaid +sequenceDiagram +participant JobService as "JobService" +participant JobExecutionService as "JobExecutionService" +participant CommandService as "CommandService" +participant JobExecutionServiceImpl as "JobExecutionServiceImpl" +JobService->>JobExecutionService : getJobExecution(job, scheduleTime) +JobExecutionService-->>JobService : JobExecution +JobService->>JobExecutionService : save(jobExecution) +JobService->>CommandService : insert(command) +CommandService-->>JobService : 命令ID +JobService-->>JobExecutionServiceImpl : executeJob(jobExecution) +JobExecutionServiceImpl->>JobExecutionServiceImpl : create(jobExecution) +JobExecutionServiceImpl->>CommandService : insert(command) +CommandService-->>JobExecutionServiceImpl : 命令ID +JobExecutionServiceImpl-->>JobService : 执行ID +``` + +### 调度协作 +调度服务与其他服务的协作: + +```mermaid +sequenceDiagram +participant JobScheduleService as "JobScheduleService" +participant QuartzExecutors as "QuartzExecutors" +participant JobService as "JobService" +participant JobExternalService as "JobExternalService" +JobScheduleService->>QuartzExecutors : addJob(DataQualityScheduleJob, schedule) +QuartzExecutors-->>JobScheduleService : 调度结果 +QuartzExecutors->>DataQualityScheduleJob : execute(context) +DataQualityScheduleJob->>JobExternalService : executeJob(jobId, scheduleTime) +JobExternalService->>JobService : execute(jobId, scheduleTime) +JobService-->>JobExternalService : 执行ID +JobExternalService-->>DataQualityScheduleJob : 执行结果 +``` + +### SLA协作 +SLA服务与作业服务的协作: + +```mermaid +sequenceDiagram +participant JobService as "JobService" +participant SlaService as "SlaService" +participant JobVO as "JobVO" +JobService->>SlaService : getSlaByJobId(jobId) +SlaService-->>JobService : SLA列表 +JobService->>JobExecutionService : getJobExecutionStat(jobId) +JobExecutionService-->>JobService : 执行统计 +JobService->>JobVO : 设置SLA和统计信息 +``` + +### 数据源协作 +作业服务与数据源服务的协作: + +```mermaid +sequenceDiagram +participant JobService as "JobService" +participant DataSourceService as "DataSourceService" +participant ConnectorFactory as "ConnectorFactory" +JobService->>DataSourceService : getDataSourceById(dataSourceId) +DataSourceService-->>JobService : DataSource +JobService->>ConnectorFactory : getOrCreatePlugin(dataSourceType) +ConnectorFactory-->>JobService : ConnectorFactory +JobService->>ConnectorFactory.getDialect() : invalidateItemCanOutputToSelf() +``` + +### 服务协作最佳实践 +1. **松耦合**:通过接口定义服务契约 +2. **高内聚**:每个服务职责单一 +3. **异步通信**:使用消息队列解耦服务 +4. **超时控制**:设置合理的服务调用超时 +5. **重试机制**:实现服务调用的重试逻辑 +6. **熔断降级**:防止服务雪崩 +7. **监控告警**:监控服务调用性能 +8. **文档化**:维护服务接口文档 + +**服务协作关系** +- [JobServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobServiceImpl.java#L92-L127) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java#L57-L58) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java#L68-L75) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\345\221\212\350\255\246\346\234\215\345\212\241\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\345\221\212\350\255\246\346\234\215\345\212\241\345\256\236\347\216\260.md" new file mode 100644 index 00000000..72cdd956 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\345\221\212\350\255\246\346\234\215\345\212\241\345\256\236\347\216\260.md" @@ -0,0 +1,295 @@ +# 告警服务实现 + + +**本文档引用的文件** +- [SlaService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaService.java) +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java) +- [SlaNotificationMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationMessage.java) +- [SlaConfigMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaConfigMessage.java) +- [SlaNotificationResult.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationResult.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) + + +## 目录 +1. [引言](#引言) +2. [SLA服务核心组件](#sla服务核心组件) +3. [SLA规则配置与验证机制](#sla规则配置与验证机制) +4. [告警条件判断与触发流程](#告警条件判断与触发流程) +5. [通知策略执行机制](#通知策略执行机制) +6. [多通道告警发送实现](#多通道告警发送实现) +7. [告警历史记录与状态管理](#告警历史记录与状态管理) +8. [动态阈值计算逻辑](#动态阈值计算逻辑) +9. [告警去重、抑制与升级策略](#告警去重抑制与升级策略) +10. [高可靠性告警系统最佳实践](#高可靠性告警系统最佳实践) + +## 引言 +本文档详细阐述了DataVines平台中SlaService和SlaNotificationService服务的实现机制。重点解析SLA(服务等级协议)规则的配置、验证和触发流程,深入分析告警条件判断、通知策略执行和告警历史记录的完整生命周期。文档还详细说明了服务层如何通过NotificationManager实现钉钉、邮件等多通道告警发送,以及SLA规则与作业、数据质量指标的关联关系。 + +## SLA服务核心组件 + +SlaService和SlaNotificationService是DataVines平台中负责SLA规则管理和告警通知的核心服务组件。SlaService主要负责SLA规则的增删改查、支持的插件类型查询以及与作业的关联查询。SlaNotificationService则专注于告警通知的配置管理、接收方信息获取和通知记录的分页查询。 + +```mermaid +classDiagram +class SlaService { ++listSlas(workspaceId, searchVal, pageNumber, pageSize) IPage~SlaPageVO~ ++deleteById(id) boolean ++getSenderConfigJson(type) String ++getSupportPlugin() Set~String~ ++createSla(create) Sla ++updateSla(update) boolean ++getSlaByJobId(jobId) SlaVO[] ++getSlaConfigByJobId(jobId) SlaConfigVO[] +} +class SlaNotificationService { ++getSlasNotificationConfigurationBySlasId(slaId) Map~SlaSenderMessage, Set~SlaConfigMessage~~ ++getSlasNotificationConfigurationBySlasIdAndSenderId(slaId, senderId, config) Map~SlaSenderMessage, Set~SlaConfigMessage~~ ++getSlasNotificationConfigurationByJobId(job) Map~SlaSenderMessage, Set~SlaConfigMessage~~ ++getConfigJson(type) String ++createNotification(create) SlaNotification ++updateNotification(update) SlaNotification ++pageListNotification(workspaceId, slaId, searchVal, pageNumber, pageSize) IPage~SlaNotification~ ++listReceiverMessageBySlaId(id) Set~SlaConfigMessage~ ++pageListNotification(page, workspaceId, slaId, searchVal) IPage~SlaNotification~ +} +SlaService --> SlaNotificationService : "依赖" +``` + +**图示来源** +- [SlaService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaService.java) +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) + +**本节来源** +- [SlaService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaService.java) +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) + +## SLA规则配置与验证机制 + +SLA规则的配置通过SlaService提供的接口进行管理,支持对不同通知通道的配置信息进行获取和验证。系统通过`getSenderConfigJson`方法获取指定类型通知发送器的JSON配置模板,该模板定义了配置项的结构、验证规则和默认值。 + +```mermaid +flowchart TD +Start([开始]) --> GetConfigTemplate["获取配置模板"] +GetConfigTemplate --> ValidateConfig["验证用户输入配置"] +ValidateConfig --> SaveConfig["保存配置到数据库"] +SaveConfig --> End([结束]) +subgraph "配置模板生成" +GetConfigTemplate --> BuildParams["构建参数列表"] +BuildParams --> SerializeJSON["序列化为JSON"] +SerializeJSON --> ReturnTemplate["返回模板"] +end +``` + +**图示来源** +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) + +**本节来源** +- [SlaService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaService.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java) + +## 告警条件判断与触发流程 + +告警的触发流程始于SLA规则的评估结果。当数据质量检查结果违反预设的SLA阈值时,系统会创建告警通知消息并触发通知流程。SlaNotificationService负责根据SLA规则ID获取相应的通知配置,包括发送器和接收方信息。 + +```mermaid +sequenceDiagram +participant Job as "作业执行" +participant SlaService as "SlaService" +participant SlaNotificationService as "SlaNotificationService" +participant NotificationManager as "NotificationManager" +Job->>SlaService : 检查SLA规则 +SlaService->>SlaService : 评估规则条件 +alt 规则违反 +SlaService->>SlaNotificationService : 获取通知配置 +SlaNotificationService-->>SlaService : 返回配置 +SlaService->>NotificationManager : 发送告警通知 +end +``` + +**图示来源** +- [SlaService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaService.java) +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) + +**本节来源** +- [SlaService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaService.java) +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) + +## 通知策略执行机制 + +通知策略的执行由SlaNotificationService和NotificationManager协同完成。SlaNotificationService首先根据SLA规则获取完整的通知配置,然后由NotificationManager统一调度具体的告警发送插件。 + +```mermaid +flowchart TD +A[开始] --> B[获取SLA通知配置] +B --> C{配置存在?} +C --> |是| D[构建通知消息] +C --> |否| E[抛出异常] +D --> F[调用NotificationManager] +F --> G[遍历发送器类型] +G --> H{支持的插件?} +H --> |是| I[调用具体插件] +H --> |否| J[抛出异常] +I --> K[合并结果] +K --> L[返回最终结果] +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) + +**本节来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) + +## 多通道告警发送实现 + +多通道告警发送基于SPI(Service Provider Interface)插件机制实现。系统通过NotificationManager统一管理所有支持的告警通道插件,如钉钉、邮件、飞书和企业微信机器人。每个通道通过实现SlasHandlerPlugin接口提供具体的发送逻辑。 + +```mermaid +classDiagram +class NotificationManager { +-supportedPlugins Set~String~ ++notify(slaNotificationMessage, config) SlaNotificationResult +} +class SlasHandlerPlugin { +<> ++notify(slaNotificationMessage, config) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class EmailSlasHandlerPlugin { ++notify(slaNotificationMessage, config) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class DingTalkSlasHandlerPlugin { ++notify(slaNotificationMessage, config) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +NotificationManager --> SlasHandlerPlugin : "依赖" +SlasHandlerPlugin <|-- EmailSlasHandlerPlugin +SlasHandlerPlugin <|-- DingTalkSlasHandlerPlugin +``` + +**图示来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) + +**本节来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java) + +## 告警历史记录与状态管理 + +系统通过SlaNotificationService提供告警历史记录的管理和查询功能。每次告警发送的结果都会被记录,包括发送状态、时间戳和详细信息。这些记录可用于后续的审计、分析和故障排查。 + +```mermaid +classDiagram +class SlaNotificationMessage { ++Long slaId ++String subject ++String message +} +class SlaNotificationResult { ++Boolean status ++SlaNotificationResultRecord[] records ++merge(other) SlaNotificationResult +} +class SlaNotificationResultRecord { ++String senderType ++Boolean status ++String message ++Long timestamp +} +class SlaConfigMessage { ++Long id ++String type ++String config +} +class SlaSenderMessage { ++Long id ++String type ++String config +} +SlaNotificationResult --> SlaNotificationResultRecord : "包含" +SlaNotificationService --> SlaNotificationMessage : "使用" +SlaNotificationService --> SlaNotificationResult : "返回" +SlaNotificationService --> SlaConfigMessage : "使用" +SlaNotificationService --> SlaSenderMessage : "使用" +``` + +**图示来源** +- [SlaNotificationMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationMessage.java) +- [SlaNotificationResult.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationResult.java) +- [SlaConfigMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaConfigMessage.java) + +**本节来源** +- [SlaNotificationMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationMessage.java) +- [SlaNotificationResult.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationResult.java) + +## 动态阈值计算逻辑 + +虽然当前文档未直接展示动态阈值计算的具体实现,但系统架构支持通过数据质量指标的历史数据进行动态阈值计算。SLA规则可以关联特定的数据质量指标,系统可以根据指标的历史表现自动调整告警阈值,提高告警的准确性和适应性。 + +```mermaid +flowchart LR +A[数据质量指标] --> B[历史数据收集] +B --> C[趋势分析] +C --> D[动态阈值计算] +D --> E[SLA规则更新] +E --> F[告警触发判断] +``` + +**本节来源** +- [SlaService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaService.java) +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) + +## 告警去重、抑制与升级策略 + +系统通过告警历史记录和状态管理机制实现基本的告警去重和抑制功能。当相同类型的告警在短时间内重复发生时,系统可以根据配置策略决定是否合并或抑制告警通知。升级策略则通过配置多个接收方和不同的通知通道来实现。 + +```mermaid +flowchart TD +A[新告警产生] --> B{是否重复?} +B --> |是| C[检查抑制策略] +C --> D{在抑制期内?} +D --> |是| E[抑制告警] +D --> |否| F[发送告警] +B --> |否| F +F --> G{需要升级?} +G --> |是| H[发送到升级通道] +G --> |否| I[发送到默认通道] +``` + +**本节来源** +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) + +## 高可靠性告警系统最佳实践 + +为确保告警系统的高可靠性,建议采用以下最佳实践:集成消息队列实现异步告警发送,避免阻塞主业务流程;实现失败重试机制,确保重要告警不会丢失;通过性能监控及时发现和解决系统瓶颈;合理配置告警去重和抑制策略,避免告警风暴。 + +```mermaid +graph TB +subgraph "高可靠性设计" +A[异步处理] --> B[消息队列] +B --> C[消费者处理] +C --> D[失败重试] +D --> E[死信队列] +F[性能监控] --> G[指标收集] +G --> H[告警] +I[配置管理] --> J[去重策略] +I --> K[抑制策略] +end +``` + +**本节来源** +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) +- [SlaNotificationService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\SlaNotificationService.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\346\211\247\350\241\214\346\234\215\345\212\241\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\346\211\247\350\241\214\346\234\215\345\212\241\345\256\236\347\216\260.md" new file mode 100644 index 00000000..3757f3cd --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\346\211\247\350\241\214\346\234\215\345\212\241\345\256\236\347\216\260.md" @@ -0,0 +1,435 @@ +# 执行服务实现 + + +**本文档引用的文件** +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [JobExecutionResponseContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseContext.java) +- [JobExecution.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobExecution.java) +- [JobExecutionResult.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobExecutionResult.java) +- [Command.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\Command.java) +- [JobExecutionCache.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionCache.java) +- [JobExecutionContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionContext.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细描述了DataVines平台中JobExecutionService服务的实现,重点阐述作业执行实例的管理功能。该服务负责执行记录的生成、状态更新、日志查询和结果分析,与JobExecuteManager协同工作处理来自执行引擎的实时响应。文档还解释了执行结果的持久化策略,以及执行上下文(JobExecutionResponseContext)在状态跟踪中的作用。此外,文档说明了执行历史数据的分页查询、趋势分析和性能监控实现,并提供了大规模执行实例管理的优化方案。 + +## 项目结构 +DataVines项目的执行服务主要位于`datavines-server`模块中,涉及多个子包和组件。核心的执行服务实现位于`repository/service`包中,而执行协调和缓存管理则位于`dqc/coordinator/cache`包中。执行相关的实体类定义在`repository/entity`包中,而执行上下文和缓存机制则在`dqc/executor/cache`包中实现。 + +```mermaid +graph TB +subgraph "datavines-server" +subgraph "repository/service" +JobExecutionService[JobExecutionService] +JobExecutionServiceImpl[JobExecutionServiceImpl] +end +subgraph "dqc/coordinator/cache" +JobExecuteManager[JobExecuteManager] +JobExecutionResponseContext[JobExecutionResponseContext] +end +subgraph "repository/entity" +JobExecution[JobExecution] +JobExecutionResult[JobExecutionResult] +Command[Command] +end +subgraph "dqc/executor/cache" +JobExecutionCache[JobExecutionCache] +JobExecutionContext[JobExecutionContext] +end +JobExecutionService --> JobExecutionServiceImpl +JobExecuteManager --> JobExecutionResponseContext +JobExecutionServiceImpl --> JobExecution +JobExecutionServiceImpl --> JobExecutionResult +JobExecuteManager --> JobExecutionCache +JobExecuteManager --> JobExecutionContext +JobExecuteManager --> JobExecutionServiceImpl +end +``` + +**图源** +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [JobExecutionResponseContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseContext.java) +- [JobExecution.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobExecution.java) +- [JobExecutionResult.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobExecutionResult.java) +- [Command.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\Command.java) +- [JobExecutionCache.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionCache.java) +- [JobExecutionContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionContext.java) + +**章节源** +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +## 核心组件 +JobExecutionService是DataVines平台中负责管理作业执行实例的核心服务。它提供了创建、更新、查询和删除作业执行记录的功能,同时支持执行结果的持久化和状态跟踪。该服务与JobExecuteManager紧密协作,处理来自执行引擎的实时响应,并通过JobExecutionResponseContext对象在系统组件间传递执行状态信息。 + +**章节源** +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) + +## 架构概述 +JobExecutionService的架构设计采用了分层模式,将业务逻辑、数据访问和执行协调分离。服务层负责处理业务逻辑,通过JobExecuteManager协调作业执行过程,并将执行结果持久化到数据库中。执行上下文通过JobExecutionCache进行管理,确保执行状态的一致性和可追溯性。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant JobExecutionService as "JobExecutionService" +participant JobExecuteManager as "JobExecuteManager" +participant JobExecutionCache as "JobExecutionCache" +participant Database as "数据库" +Client->>JobExecutionService : submitJob(SubmitJob) +JobExecutionService->>JobExecutionService : 创建JobExecution +JobExecutionService->>JobExecuteManager : addExecuteCommand(JobExecution) +JobExecuteManager->>JobExecutionCache : cache(JobExecutionContext) +JobExecuteManager->>JobExecutionService : 更新执行状态 +JobExecutionService->>Database : 持久化执行记录 +Database-->>JobExecutionService : 返回执行ID +JobExecutionService-->>Client : 返回执行ID +Note over Client,Database : 作业提交流程 +JobExecuteManager->>JobExecuteManager : 处理执行响应 +JobExecuteManager->>JobExecutionService : 更新最终状态 +JobExecutionService->>Database : 更新执行结果 +``` + +**图源** +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [JobExecutionCache.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionCache.java) + +## 详细组件分析 + +### JobExecutionService分析 +JobExecutionService接口定义了作业执行管理的核心功能,包括创建、更新、查询作业执行记录,以及提交和执行作业。其实现类JobExecutionServiceImpl通过MyBatis Plus框架与数据库交互,实现了这些功能。 + +#### 服务接口分析 +```mermaid +classDiagram +class JobExecutionService { ++long create(JobExecution jobExecution) ++int update(JobExecution jobExecution) ++JobExecution getById(long id) ++List listByJobId(long jobId) ++int deleteByJobId(long jobId) ++IPage getJobExecutionPage(JobExecutionPageParam pageParam) ++Long submitJob(SubmitJob submitJob) ++Long executeJob(JobExecution jobExecution) ++Long killJob(Long taskId) ++List listNeedFailover(String host) ++List listJobExecutionNotInServerList(List hostList) ++String getJobExecutionHost(Long jobExecutionId) ++List getMetricExecutionDashBoard(Long jobId, String startTime, String endTime) ++List getJobExecutionAggPie(JobExecutionDashboardParam dashboardParam) ++JobExecutionTrendBar getJobExecutionTrendBar(JobExecutionDashboardParam dashboardParam) ++JobExecutionStat getJobExecutionStat(Long jobId) +} +class JobExecutionServiceImpl { +-CommandService commandService +-JobExecutionResultService jobExecutionResultService +-JobExecutionResultMapper jobExecutionResultMapper +-ActualValuesService actualValuesService ++long create(JobExecution jobExecution) ++int update(JobExecution jobExecution) ++JobExecution getById(long id) ++List listByJobId(long jobId) ++int deleteByJobId(long jobId) ++IPage getJobExecutionPage(JobExecutionPageParam pageParam) ++Long submitJob(SubmitJob submitJob) ++Long executeJob(JobExecution jobExecution) ++Long killJob(Long jobExecutionId) ++List listNeedFailover(String host) ++List listJobExecutionNotInServerList(List hostList) ++String getJobExecutionHost(Long jobExecutionId) ++List getMetricExecutionDashBoard(Long jobId, String startTime, String endTime) ++List getJobExecutionAggPie(JobExecutionDashboardParam dashboardParam) ++JobExecutionTrendBar getJobExecutionTrendBar(JobExecutionDashboardParam dashboardParam) ++JobExecutionStat getJobExecutionStat(Long jobId) +} +JobExecutionServiceImpl --|> JobExecutionService : 实现 +``` + +**图源** +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) + +#### 执行流程分析 +```mermaid +flowchart TD +Start([提交作业]) --> ValidateInput["验证作业参数"] +ValidateInput --> InputValid{"参数有效?"} +InputValid --> |否| ReturnError["返回错误"] +InputValid --> |是| CreateJobExecution["创建JobExecution对象"] +CreateJobExecution --> SetStatus["设置状态为SUBMITTED_SUCCESS"] +SetStatus --> CreateRecord["在数据库中创建执行记录"] +CreateRecord --> CreateCommand["创建Command对象"] +CreateCommand --> SetCommand["设置命令类型为START"] +SetCommand --> InsertCommand["插入命令到数据库"] +InsertCommand --> ReturnId["返回执行ID"] +ReturnId --> End([完成]) +style Start fill:#f9f,stroke:#333 +style End fill:#f9f,stroke:#333 +``` + +**图源** +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) + +**章节源** +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) + +### JobExecuteManager分析 +JobExecuteManager是作业执行的核心协调器,负责管理作业执行的生命周期。它通过线程池处理作业执行请求,并通过响应队列处理来自执行引擎的响应。 + +#### 协调器架构分析 +```mermaid +classDiagram +class JobExecuteManager { +-LinkedBlockingQueue responseQueue +-ExecutorService executorService +-ExecutorService jobExecuteService +-JobExternalService jobExternalService +-JobExecutionCache jobExecutionCache +-HashedWheelTimer wheelTimer +-Configurations configurations +-JobResultValidator jobResultValidator +-NotificationClient notificationClient +-DataSourceService dataSourceService +-SlaNotificationService slaNotificationService +-ConcurrentHashMap> engine2Execution ++void start() ++void addKillCommand(Long jobExecutionId) ++void processJobExecutionExecuteResponse(JobExecuteResponseCommand) ++void processJobExecutionAckResponse(JobExecuteAckCommand) ++void close() ++void addFailoverJobExecutionRequest(JobExecution) ++void addEngine2ExecutionMap(String, Long) ++void minusEngine2ExecutionMap(String, Long) ++int getExecutionCountByEngine(String) ++void addExecuteCommand(JobExecution) ++static JobExecutionRequest buildJobExecutionRequest(JobExecution) +} +class JobExecutionExecutor { ++run() +} +class JobExecutionResponseOperator { ++run() +} +class JobExecutionTimeoutTimerTask { ++run(Timeout) +} +JobExecuteManager --> JobExecutionExecutor : 包含 +JobExecuteManager --> JobExecutionResponseOperator : 包含 +JobExecuteManager --> JobExecutionTimeoutTimerTask : 包含 +JobExecuteManager --> JobExecutionCache : 使用 +JobExecuteManager --> JobExternalService : 使用 +``` + +**图源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +#### 执行响应处理流程 +```mermaid +sequenceDiagram +participant JobExecuteManager +participant JobExecutionResponseOperator +participant JobExternalService +participant JobResultValidator +JobExecuteManager->>JobExecutionResponseOperator : 接收响应 +JobExecutionResponseOperator->>JobExecutionResponseOperator : 从队列获取响应 +JobExecutionResponseOperator->>JobExternalService : 获取JobExecution +JobExecutionResponseOperator->>JobExecutionResponseOperator : 根据命令码处理 +alt JOB_EXECUTE_ACK +JobExecutionResponseOperator->>JobExternalService : 更新执行状态为RUNNING +else JOB_EXECUTE_RESPONSE +alt 成功 +JobExecutionResponseOperator->>JobResultValidator : 验证执行结果 +JobResultValidator->>JobExternalService : 持久化结果 +JobExecutionResponseOperator->>JobExternalService : 更新状态为SUCCESS +else 失败 +JobExecutionResponseOperator->>JobExecuteManager : 检查重试次数 +alt 需要重试 +JobExecuteManager->>JobExecuteManager : 提交重试命令 +JobExecuteManager->>JobExternalService : 更新重试次数 +else 无需重试 +JobExecuteManager->>JobExternalService : 发送错误通知 +JobExecuteManager->>JobExternalService : 更新状态为FAILURE +end +end +end +``` + +**图源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +**章节源** +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +### 执行上下文分析 +执行上下文是作业执行过程中的核心数据结构,用于在系统组件间传递执行信息和状态。 + +#### JobExecutionResponseContext分析 +```mermaid +classDiagram +class JobExecutionResponseContext { +-CommandCode commandCode +-JobExecutionRequest jobExecutionRequest ++JobExecutionResponseContext() ++JobExecutionResponseContext(CommandCode, JobExecutionRequest) +} +class CommandCode { ++JOB_EXECUTE_REQUEST ++JOB_EXECUTE_RESPONSE ++JOB_EXECUTE_ACK ++JOB_KILL_REQUEST +} +class JobExecutionRequest { +-Long jobExecutionId +-String jobExecutionName +-String executePlatformType +-String executePlatformParameter +-String engineType +-String engineParameter +-String errorDataStorageType +-String errorDataStorageParameter +-String errorDataFileName +-String validateResultDataStorageType +-String validateResultDataStorageParameter +-JobExecutionParameter jobExecutionParameter +-ExecutionStatus status +-Integer retryTimes +-Integer retryInterval +-Integer timeout +-TimeoutStrategy timeoutStrategy +-String preSql +-String postSql +-String tenantCode +-String executeHost +-String applicationId +-String applicationParameter +-String logPath +-String executeFilePath +-String env +-LocalDateTime startTime +-LocalDateTime endTime +-String jobExecutionUniqueId +-int processId +} +JobExecutionResponseContext --> CommandCode : 引用 +JobExecutionResponseContext --> JobExecutionRequest : 包含 +``` + +**图源** +- [JobExecutionResponseContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseContext.java) + +#### JobExecutionCache分析 +```mermaid +classDiagram +class JobExecutionCache { +-ConcurrentHashMap cache ++static JobExecutionCache getInstance() ++JobExecutionContext getById(Long) ++void cache(JobExecutionContext) ++void remove(Long) +} +class JobExecutionContext { +-JobExecutionRequest jobExecutionRequest +-JobRunner jobRunner +} +class JobRunner { +-JobExecutionRequest jobExecutionRequest +-Configurations configurations ++void run() ++void kill() +} +JobExecutionCache --> JobExecutionContext : 管理 +JobExecutionContext --> JobExecutionRequest : 包含 +JobExecutionContext --> JobRunner : 包含 +``` + +**图源** +- [JobExecutionCache.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionCache.java) +- [JobExecutionContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionContext.java) + +**章节源** +- [JobExecutionResponseContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecutionResponseContext.java) +- [JobExecutionCache.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionCache.java) +- [JobExecutionContext.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionContext.java) + +## 依赖分析 +JobExecutionService及其相关组件依赖于多个核心服务和工具类,形成了一个复杂的依赖网络。 + +```mermaid +graph TD +JobExecutionService --> JobExecutionServiceImpl +JobExecutionServiceImpl --> JobExecutionMapper +JobExecutionServiceImpl --> CommandService +JobExecutionServiceImpl --> JobExecutionResultService +JobExecutionServiceImpl --> ActualValuesService +JobExecutionServiceImpl --> JobExternalService +JobExecuteManager --> JobExecutionCache +JobExecuteManager --> JobExternalService +JobExecuteManager --> JobResultValidator +JobExecuteManager --> NotificationClient +JobExecuteManager --> DataSourceService +JobExecuteManager --> SlaNotificationService +JobExecuteManager --> SpringApplicationContext +JobExecutionCache --> JobExecutionContext +JobExecutionContext --> JobRunner +JobRunner --> JobExecutionRequest +JobRunner --> Configurations +``` + +**图源** +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) +- [JobExecutionCache.java](file://datavines-server\src\main\java\io\datavines\server\dqc\executor\cache\JobExecutionCache.java) + +**章节源** +- [JobExecutionService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +## 性能考虑 +对于大规模执行实例的管理,系统提供了多种优化方案: + +1. **数据归档**:通过定期归档历史执行记录,减少主表的数据量,提高查询性能。 +2. **索引优化**:在关键字段(如job_id、status、create_time)上创建复合索引,加速查询操作。 +3. **缓存策略**:使用JobExecutionCache缓存正在执行的作业上下文,避免频繁的数据库访问。 +4. **分页查询**:提供分页查询接口,避免一次性加载大量数据。 +5. **异步处理**:使用线程池异步处理作业执行和响应,提高系统吞吐量。 + +**章节源** +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +## 故障排除指南 +当作业执行出现问题时,可以按照以下步骤进行排查: + +1. **检查执行状态**:通过`getJobExecutionHost`方法确认作业是否已分配执行主机。 +2. **查看执行日志**:根据`logPath`字段定位日志文件,分析执行过程中的错误信息。 +3. **检查重试机制**:确认`retryTimes`和`retryInterval`配置是否合理。 +4. **验证超时设置**:检查`timeout`和`timeoutStrategy`配置,确保不会因超时导致作业失败。 +5. **监控资源使用**:通过`getExecutionCountByEngine`方法监控各执行引擎的负载情况。 + +**章节源** +- [JobExecutionServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExecutionServiceImpl.java) +- [JobExecuteManager.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\cache\JobExecuteManager.java) + +## 结论 +JobExecutionService及其相关组件构成了DataVines平台作业执行管理的核心。通过分层架构设计和清晰的职责划分,系统实现了作业执行的全生命周期管理。执行服务与协调器、缓存机制紧密协作,确保了执行过程的可靠性和可追溯性。对于大规模执行实例的管理,系统提供了多种优化方案,包括数据归档、索引优化和缓存策略,能够有效应对高并发场景下的性能挑战。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\346\225\260\346\215\256\346\272\220\346\234\215\345\212\241\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\346\225\260\346\215\256\346\272\220\346\234\215\345\212\241\345\256\236\347\216\260.md" new file mode 100644 index 00000000..8aa71257 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\346\225\260\346\215\256\346\272\220\346\234\215\345\212\241\345\256\236\347\216\260.md" @@ -0,0 +1,490 @@ +# 数据源服务实现 + + +**本文引用的文件列表** +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java) +- [DataSourceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml) +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java) +- [PostgreSqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnectorFactory.java) +- [JobServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobServiceImpl.java) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java) +- [CommonTaskMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/CommonTaskMapper.java) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) +- [JdbcExecutorClientManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClientManager.java) +- [ConnectionHolder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/entity/ConnectionHolder.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件围绕数据源服务(DataSourceService)展开,系统性阐述其在DataVines中的职责与实现细节,包括: +- 数据源配置的增删改查(CRUD)实现 +- 敏感信息(如密码)的加密存储与脱敏展示流程 +- 数据源测试连接功能的实现机制及与datavines-connector模块的协作 +- 数据源与作业、任务之间的关联关系管理 +- 多租户环境下的数据隔离策略 +- 服务层使用MyBatis Plus的Wrapper进行复杂查询构建 +- DataSourceMapper.xml中动态SQL的实现要点 +- 数据源配置校验、连接池管理与性能监控建议 + +## 项目结构 +围绕数据源服务的关键文件分布如下: +- 接口与实现:服务接口与实现类位于服务层 +- 映射器与XML:MyBatis映射器与动态SQL位于资源目录 +- 控制器:对外暴露REST接口 +- 实体:数据源实体模型 +- 工具与日志:加密工具、密码过滤与日志脱敏 +- 连接器:通过插件化ConnectorFactory与Connector接口验证连接 +- 关联服务:作业、任务、租户等服务用于管理数据源与业务对象的关系 + +```mermaid +graph TB +subgraph "服务层" +DSvcI["DataSourceService 接口"] +DSvcImpl["DataSourceServiceImpl 实现"] +JobSvc["JobServiceImpl"] +JobExtSvc["JobExternalService"] +CommonTaskMapper["CommonTaskMapper"] +end +subgraph "持久层" +DSvcMapper["DataSourceMapper 接口"] +DSvcXml["DataSourceMapper.xml 动态SQL"] +DSvcEntity["DataSource 实体"] +end +subgraph "控制器" +DSvcCtl["DataSourceController 控制器"] +end +subgraph "工具与日志" +Crypt["CryptionUtils 加密解密"] +PwdFilter["PasswordFilterUtils 脱敏"] +SensitiveConv["SensitiveDataConverter 日志脱敏"] +end +subgraph "连接器" +ConnIF["Connector 接口"] +AbsJdbcCF["AbstractJdbcConnectorFactory"] +PgCF["PostgreSqlConnectorFactory"] +end +DSvcCtl --> DSvcImpl +DSvcImpl --> DSvcMapper +DSvcImpl --> DSvcEntity +DSvcImpl --> Crypt +DSvcImpl --> PwdFilter +DSvcImpl --> SensitiveConv +DSvcImpl --> ConnIF +DSvcImpl --> AbsJdbcCF +DSvcImpl --> PgCF +DSvcImpl --> JobSvc +DSvcImpl --> JobExtSvc +DSvcImpl --> CommonTaskMapper +DSvcMapper --> DSvcXml +``` + +图表来源 +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java#L1-L59) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L1-L357) +- [DataSourceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java#L1-L33) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L1-L37) +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L26-L119) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java#L1-L70) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L1-L85) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L1-L77) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L1-L60) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java#L36-L62) +- [PostgreSqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnectorFactory.java#L35-L57) + +章节来源 +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java#L1-L59) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L1-L357) +- [DataSourceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java#L1-L33) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L1-L37) +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L26-L119) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java#L1-L70) + +## 核心组件 +- 服务接口与实现 + - 接口定义了数据源的增删改查、分页查询、数据库/表/列枚举、脚本执行、连接测试、配置JSON获取等能力 + - 实现类负责参数校验、加密存储、解密返回、调用连接器进行连接测试与元数据获取、触发相关任务调度 +- 映射器与XML + - 提供分页查询与动态条件拼装,支持按工作空间与名称模糊检索 +- 控制器 + - 对外提供REST接口,封装请求参数并调用服务层 +- 实体 + - 定义数据源字段,包含工作空间标识、类型、参数、参数摘要、创建/更新时间与用户等 +- 工具与日志 + - AES加解密工具、密码脱敏工具、日志脱敏转换器 +- 连接器 + - 通过SPI加载不同类型的连接器工厂,统一调用测试连接、获取数据库/表/列、执行脚本等 + +章节来源 +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java#L1-L59) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L1-L357) +- [DataSourceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java#L1-L33) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L1-L37) +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L26-L119) +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java#L1-L70) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L1-L85) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L1-L77) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L1-L60) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) + +## 架构总览 +下图展示了数据源服务从控制器到服务、映射器、连接器以及相关业务服务的整体交互。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Ctrl as "DataSourceController" +participant Svc as "DataSourceServiceImpl" +participant Mapper as "DataSourceMapper" +participant Xml as "DataSourceMapper.xml" +participant Conn as "ConnectorFactory/Connector" +participant Job as "JobServiceImpl" +participant Task as "CommonTaskMapper" +Client->>Ctrl : "POST /datasource/test" +Ctrl->>Svc : "testConnect(param)" +Svc->>Conn : "getOrCreatePlugin(type).getConnector().testConnect(param)" +Conn-->>Svc : "ConnectorResponse{result}" +Svc-->>Ctrl : "boolean" +Ctrl-->>Client : "结果" +Client->>Ctrl : "POST /datasource" +Ctrl->>Svc : "insert(createBO)" +Svc->>Svc : "参数校验/加密/AES" +Svc->>Mapper : "insert(entity)" +Svc->>Job : "刷新目录/创建质量报告计划" +Svc-->>Ctrl : "id" +Ctrl-->>Client : "id" +Client->>Ctrl : "GET /datasource/page?pageNumber&pageSize&workSpaceId" +Ctrl->>Svc : "getDataSourcePage(...)" +Svc->>Mapper : "getDataSourcePage(page, searchVal, workspaceId)" +Mapper->>Xml : "执行动态SQL" +Xml-->>Mapper : "IPage" +Mapper-->>Svc : "IPage" +Svc->>Svc : "解密参数/脱敏密码" +Svc-->>Ctrl : "IPage" +Ctrl-->>Client : "分页结果" +``` + +图表来源 +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L26-L119) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L76-L147) +- [DataSourceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java#L1-L33) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L1-L37) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) + +## 详细组件分析 + +### 数据源服务接口与实现 +- 增删改查与分页 + - 插入:生成UUID、计算参数摘要、加密参数后入库;同时触发目录刷新与质量报告计划创建 + - 更新:重新计算参数摘要并加密参数后更新 + - 删除:删除前清理目录实体、作业与任务,再删除数据源 + - 查询:按工作空间与类型筛选;分页查询时对返回参数进行解密与密码脱敏 +- 元数据与脚本 + - 获取数据库/表/列列表:基于连接器工厂获取对应实现 + - 执行脚本:将脚本交由连接器执行器执行 +- 连接测试 + - 通过插件化连接器工厂调用测试连接方法,返回布尔结果 + +```mermaid +classDiagram +class DataSourceService { ++boolean testConnect(param) ++long insert(create) ++int update(update) ++DataSource getDataSourceById(id) ++int delete(id) ++DataSource[] listByWorkSpaceId(workspaceId) ++IPage~DataSourceVO~ getDataSourcePage(searchVal, workspaceId, pageNumber, pageSize) ++Object getDatabaseList(id) ++Object getTableList(id, database) ++Object getColumnList(id, database, table) ++Object executeScript(request) ++String getConfigJson(type) ++DataSource[] listByWorkSpaceIdAndType(workspaceId, type) +} +class DataSourceServiceImpl { ++boolean testConnect(param) ++long insert(create) ++int update(update) ++DataSource getDataSourceById(id) ++int delete(id) ++IPage~DataSourceVO~ getDataSourcePage(searchVal, workspaceId, pageNumber, pageSize) ++DataSource[] listByWorkSpaceId(workspaceId) ++DataSource[] listByWorkSpaceIdAndType(workspaceId, type) ++Object getDatabaseList(id) ++Object getTableList(id, database) ++Object getColumnList(id, database, table) ++Object executeScript(request) ++String getConfigJson(type) +} +DataSourceService <|.. DataSourceServiceImpl +``` + +图表来源 +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java#L1-L59) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L1-L357) + +章节来源 +- [DataSourceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java#L1-L59) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L76-L356) + +### 敏感信息加密与脱敏 +- 存储加密 + - 在插入与更新时,将参数字符串使用AES进行加密存储 + - 使用固定IV与密钥进行加解密,确保可逆 +- 返回脱敏 + - 分页查询与单条查询时,先解密参数,再对密码字段进行脱敏显示 +- 日志脱敏 + - 日志过滤器通过正则匹配并替换敏感字段,避免日志泄露 + +```mermaid +flowchart TD +Start(["开始"]) --> Encrypt["加密参数(AES)"] +Encrypt --> Save["保存到数据库"] +Save --> Query["查询数据源"] +Query --> Decrypt["解密参数(AES)"] +Decrypt --> MaskPwd["脱敏密码字段"] +MaskPwd --> Return(["返回结果"]) +``` + +图表来源 +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L112-L146) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L184-L196) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L240-L256) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L1-L85) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L1-L77) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L1-L60) + +章节来源 +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L1-L85) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L1-L77) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L1-L60) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L112-L146) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L184-L196) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L240-L256) + +### 测试连接与datavines-connector协作 +- 通过SPI加载指定类型的连接器工厂,调用连接器的测试连接方法 +- 连接器接口定义了默认空实现,具体数据库类型由各插件实现 +- JDBC通用工厂提供数据源客户端、语句解析与度量脚本等能力 + +```mermaid +sequenceDiagram +participant Svc as "DataSourceServiceImpl" +participant Loader as "PluginLoader" +participant CF as "ConnectorFactory" +participant Conn as "Connector" +Svc->>Loader : "getOrCreatePlugin(type)" +Loader-->>Svc : "ConnectorFactory" +Svc->>CF : "getConnector()" +CF-->>Svc : "Connector" +Svc->>Conn : "testConnect(param)" +Conn-->>Svc : "ConnectorResponse{result}" +Svc-->>Svc : "返回布尔结果" +``` + +图表来源 +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L76-L80) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java#L36-L62) +- [PostgreSqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnectorFactory.java#L35-L57) + +章节来源 +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L76-L80) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java#L36-L62) +- [PostgreSqlConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnectorFactory.java#L35-L57) + +### 数据源与作业、任务的关联关系 +- 删除数据源时,会级联删除目录实体、作业与任务,防止悬挂引用 +- 新增数据源后,自动创建目录元数据抓取任务与质量报告周期任务 +- 作业服务与外部作业服务均持有数据源服务引用,便于在执行过程中使用数据源配置 + +```mermaid +flowchart TD +DelStart(["删除数据源"]) --> CleanCat["删除目录实体(uuid)"] +CleanCat --> CleanJobs["删除作业(按数据源id)"] +CleanJobs --> CleanTasks["删除任务(按数据源id)"] +CleanTasks --> RemoveDS["删除数据源记录"] +RemoveDS --> DelEnd(["完成"]) +NewDS(["新增数据源"]) --> RefreshCat["刷新目录元数据任务"] +RefreshCat --> QualityPlan["创建质量报告周期任务"] +QualityPlan --> NewEnd(["完成"]) +``` + +图表来源 +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L224-L237) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L127-L146) +- [JobServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobServiceImpl.java#L98-L124) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java#L43-L72) + +章节来源 +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L224-L237) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L127-L146) +- [JobServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobServiceImpl.java#L98-L124) +- [JobExternalService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExternalService.java#L43-L72) + +### 多租户环境下的数据隔离策略 +- 数据源实体包含工作空间标识字段,查询与分页均以该字段作为过滤条件 +- 列表查询与分页查询均通过Wrapper或XML动态SQL限制在当前工作空间内 +- 租户服务提供按工作空间的租户管理能力,确保业务对象与数据源在同一工作空间内隔离 + +```mermaid +flowchart TD +WS["工作空间ID(workspaceId)"] --> Filter["过滤条件(Wrapper/XML)"] +Filter --> Query["查询数据源"] +Query --> Result["返回结果(仅限当前工作空间)"] +``` + +图表来源 +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java#L1-L70) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L258-L266) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L23-L36) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java#L1-L39) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java#L1-L38) + +章节来源 +- [DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java#L1-L70) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L258-L266) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L23-L36) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java#L1-L39) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java#L1-L38) + +### MyBatis Plus Wrapper与动态SQL +- Wrapper复杂查询 + - 使用Lambda表达式构建等值条件,如按工作空间与类型筛选 +- 动态SQL + - XML中通过标签实现条件拼装与模糊匹配 + - 支持按工作空间过滤与可选的名称模糊查询 + +```mermaid +flowchart TD +Build["构建QueryWrapper(lambda)"] --> EqWS["eq(workspaceId)"] +EqWS --> EqType["eq(type)"] +EqType --> Select["selectList(...)"] +DynSQL["DataSourceMapper.xml"] --> Basic[""] +Basic --> Where[" 条件拼装"] +Where --> Like["LOWER(name) LIKE %searchVal%"] +Like --> Order["order by update_time desc"] +``` + +图表来源 +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L258-L266) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L23-L36) + +章节来源 +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L258-L266) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L23-L36) + +### 数据源配置校验、连接池管理与性能监控建议 +- 配置校验 + - 插入与更新前对参数Map进行非空校验,提取关键属性用于参数摘要计算 + - 使用连接器工厂提供的keyProperties集合,确保必要字段存在 +- 连接池管理 + - 通用JDBC连接器工厂提供数据源客户端,可结合应用侧连接池配置 + - 引擎本地模式下提供连接持有者,按需重建连接并校验有效性 +- 性能监控 + - JDBC工具类提供查询耗时统计与日志输出,可用于监控SQL执行性能 + - 建议在连接器层增加连接池大小、超时、重试等配置项,并在日志中记录关键指标 + +章节来源 +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L82-L111) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L149-L181) +- [AbstractJdbcConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/AbstractJdbcConnectorFactory.java#L36-L62) +- [JdbcExecutorClientManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClientManager.java#L1-L37) +- [ConnectionHolder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/entity/ConnectionHolder.java#L33-L61) + +## 依赖关系分析 +- 组件耦合 + - 服务实现依赖映射器、实体、工具类与连接器SPI + - 控制器仅依赖服务接口,保持良好的分层 +- 外部依赖 + - 连接器通过SPI加载,支持多种数据库类型 + - 作业与任务服务与数据源服务存在业务关联,但通过接口解耦 + +```mermaid +graph LR +Ctrl["DataSourceController"] --> Svc["DataSourceServiceImpl"] +Svc --> Mapper["DataSourceMapper"] +Mapper --> Xml["DataSourceMapper.xml"] +Svc --> Crypt["CryptionUtils"] +Svc --> Pwd["PasswordFilterUtils"] +Svc --> Conv["SensitiveDataConverter"] +Svc --> ConnIF["Connector 接口"] +Svc --> CF["ConnectorFactory(插件)"] +Svc --> Job["JobServiceImpl/JobExternalService"] +Svc --> Task["CommonTaskMapper"] +``` + +图表来源 +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L26-L119) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L1-L357) +- [DataSourceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java#L1-L33) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L1-L37) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) + +章节来源 +- [DataSourceController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#L26-L119) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L1-L357) +- [DataSourceMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java#L1-L33) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L1-L37) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) + +## 性能考量 +- 查询性能 + - 分页查询应配合索引优化,建议在工作空间与更新时间上建立合适索引 + - 动态SQL中模糊查询可能影响性能,建议限制搜索范围或增加前缀索引 +- 加解密开销 + - AES加解密为CPU密集型操作,建议批量处理时合并请求,减少重复加解密 +- 连接池与超时 + - 合理设置连接池大小与超时时间,避免频繁创建销毁连接 + - 在连接器层增加健康检查与重试策略,提升稳定性 + +## 故障排查指南 +- 加密异常 + - 若解密失败,检查密钥长度与格式是否符合要求 + - 确认参数字符串是否被正确加密后再存储 +- 连接测试失败 + - 检查连接器类型与参数是否匹配 + - 查看连接器工厂是否正确加载 +- 分页查询无结果 + - 确认工作空间ID是否正确传入 + - 检查动态SQL条件是否生效 + +章节来源 +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L1-L85) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L76-L80) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L23-L36) + +## 结论 +数据源服务通过清晰的分层设计与插件化连接器,实现了数据源配置的全生命周期管理。服务层在保证安全性(参数加密与日志脱敏)的同时,提供了完善的测试连接、元数据枚举与脚本执行能力。通过工作空间隔离与Wrapper/动态SQL的组合,有效支撑了多租户场景下的数据隔离。建议后续进一步完善连接池配置与性能监控指标,持续优化查询与执行性能。 + +## 附录 +- 关键路径参考 + - 插入流程:[DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L82-L146) + - 更新流程:[DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L149-L196) + - 删除流程:[DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L224-L237) + - 分页查询:[DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L239-L256),[DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L23-L36) + - 连接测试:[DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L76-L80),[Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) + - 元数据与脚本:[DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L268-L350) + - 多租户隔离:[DataSource.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java#L1-L70),[DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L258-L266),[DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml#L23-L36) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260.md" new file mode 100644 index 00000000..88a3100f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260.md" @@ -0,0 +1,438 @@ +# 服务层实现 + + +**本文档中引用的文件** +- [JobService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobService.java) +- [JobServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobServiceImpl.java) +- [JobMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobMapper.java) +- [JobMapper.xml](file://datavines-server/src/main/resources/mapper/JobMapper.xml) +- [Job.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java) +- [MybatisPlusConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/MybatisPlusConfig.java) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java) +- [JobExecutionService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java) +- [JobExecutionServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java) +- [JobExecutionResultServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionResultServiceImpl.java) + + +## 目录 +1. [引言](#引言) +2. [服务层架构与设计模式](#服务层架构与设计模式) +3. [核心服务实现分析](#核心服务实现分析) +4. [MyBatis Plus使用详解](#mybatis-plus使用详解) +5. [事务管理与异常处理](#事务管理与异常处理) +6. [领域模型与数据库映射](#领域模型与数据库映射) +7. [性能优化建议](#性能优化建议) +8. [并发问题与解决方案](#并发问题与解决方案) +9. [总结](#总结) + +## 引言 +datavines-server模块的服务层是整个系统的核心业务逻辑处理中心,负责协调数据质量检查、数据剖析、数据核对等关键任务的执行。本文档将深入分析服务层的设计模式、核心服务的业务逻辑实现、MyBatis Plus的使用方式、事务管理、异常处理和日志记录机制,以及领域模型与数据库表的映射关系。 + +## 服务层架构与设计模式 +datavines-server模块的服务层采用了典型的分层架构,遵循了接口与实现分离的设计原则。每个服务都有一个接口定义和一个实现类,接口继承自MyBatis Plus的IService,提供了基本的CRUD操作。这种设计模式使得代码更加模块化,易于维护和扩展。 + +服务层通过Spring的@Service注解进行声明,并使用@Autowired注解注入其他服务依赖,实现了松耦合的组件协作。例如,JobServiceImpl类注入了JobExecutionService、CommandService、DataSourceService等多个服务,以完成复杂的业务逻辑。 + +## 核心服务实现分析 + +### JobService服务 +JobService是datavines-server模块的核心服务之一,负责管理数据质量检查任务的生命周期。该服务提供了创建、更新、删除、查询和执行任务的功能。 + +**创建任务** +`create`方法实现了任务的创建逻辑。首先对输入参数进行校验,确保任务参数不为空。然后检查目标数据源是否支持错误数据输出到自身。接着,将任务参数转换为BaseJobParameter对象列表,并进行去重和适用性检查。最后,将任务信息保存到数据库,并建立任务与实体的关联关系。 + +**更新任务** +`update`方法与`create`方法类似,但在更新前会检查任务是否存在,并确保更新后的任务名称不与其他任务冲突。更新操作同样需要进行参数校验和适用性检查。 + +**执行任务** +`execute`方法负责启动一个任务的执行。它首先获取任务信息,然后调用`executeJob`私有方法创建一个JobExecution对象,并将其保存到数据库。接着,创建一个Command对象,将其插入到命令队列中,由调度器负责后续的执行。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant JobService as "JobService" +participant JobExecutionService as "JobExecutionService" +participant CommandService as "CommandService" +Client->>JobService : execute(jobId, scheduleTime) +JobService->>JobService : getJobExecution(job, scheduleTime) +JobService->>JobExecutionService : save(jobExecution) +JobService->>CommandService : insert(command) +CommandService-->>JobService : success +JobService-->>Client : jobExecutionId +``` + +**Section sources** +- [JobServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobServiceImpl.java#L129-L249) +- [JobServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobServiceImpl.java#L533-L551) + +### JobExecutionService服务 +JobExecutionService服务负责管理任务执行的生命周期,包括任务的提交、更新、查询和删除。 + +**提交任务** +`submitJob`方法实现了任务的提交逻辑。首先对任务执行参数进行校验,然后根据任务类型设置默认的引擎参数。对于Spark引擎,设置了默认的驱动程序和执行器配置。最后,调用`executeJob`方法启动任务执行。 + +**更新任务状态** +`update`方法在更新任务执行信息时,会自动更新更新时间戳,确保数据的一致性。 + +```mermaid +classDiagram +class JobExecutionService { ++create(JobExecution jobExecution) long ++update(JobExecution jobExecution) int ++getById(long id) JobExecution ++listByJobId(long jobId) JobExecution[] ++deleteByJobId(long jobId) int ++getJobExecutionPage(JobExecutionPageParam pageParam) IPage~JobExecutionVO~ ++submitJob(SubmitJob submitJob) Long ++executeJob(JobExecution jobExecution) Long ++killJob(Long taskId) Long ++listNeedFailover(String host) JobExecution[] ++listJobExecutionNotInServerList(String[] hostList) JobExecution[] ++getJobExecutionHost(Long jobExecutionId) String ++getMetricExecutionDashBoard(Long jobId, String startTime, String endTime) MetricExecutionDashBoard[] ++getJobExecutionAggPie(JobExecutionDashboardParam dashboardParam) JobExecutionAggItem[] ++getJobExecutionTrendBar(JobExecutionDashboardParam dashboardParam) JobExecutionTrendBar ++getJobExecutionStat(Long jobId) JobExecutionStat +} +class JobExecutionServiceImpl { +-commandService CommandService +-jobExecutionResultService JobExecutionResultService +-jobExecutionResultMapper JobExecutionResultMapper +-actualValuesService ActualValuesService +} +JobExecutionService <|-- JobExecutionServiceImpl : "实现" +JobExecutionServiceImpl --> CommandService : "依赖" +JobExecutionServiceImpl --> JobExecutionResultService : "依赖" +JobExecutionServiceImpl --> JobExecutionResultMapper : "依赖" +JobExecutionServiceImpl --> ActualValuesService : "依赖" +``` + +**Section sources** +- [JobExecutionServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java#L148-L181) +- [JobExecutionServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java#L86-L89) + +## MyBatis Plus使用详解 + +### Mapper接口 +MyBatis Plus的Mapper接口继承自BaseMapper,自动提供了基本的CRUD操作。例如,JobMapper接口继承自BaseMapper,可以直接使用insert、delete、update、selectById等方法。 + +```java +@Mapper +public interface JobMapper extends BaseMapper { + @Select("SELECT * from dv_job WHERE datasource_id = #{datasourceId} ") + List listByDataSourceId(long dataSourceId); + + IPage getJobPage(Page page, + @Param("searchVal") String searchVal, + @Param("datasourceId") Long datasourceId, + @Param("type") Integer type); + + IPage getJobPageSelect(Page page, + @Param("searchVal") String searchVal, + @Param("schemaSearch") String schemaSearch, + @Param("tableSearch") String tableSearch, + @Param("columnSearch") String columnSearch, + @Param("startTime") String startTime, + @Param("endTime") String endTime, + @Param("datasourceId") Long datasourceId, + @Param("type") Integer type); +} +``` + +### XML映射文件 +对于复杂的查询,使用XML映射文件来定义SQL语句。例如,JobMapper.xml文件中定义了getJobPageSelect查询,该查询涉及多个表的连接和动态条件。 + +```xml + +``` + +### CRUD操作最佳实践 +在使用MyBatis Plus进行CRUD操作时,应遵循以下最佳实践: +1. 使用IService接口提供的通用方法,减少重复代码。 +2. 对于复杂查询,使用XML映射文件或@Select注解。 +3. 使用QueryWrapper构建动态查询条件,提高代码的可读性和可维护性。 +4. 使用分页插件进行分页查询,避免一次性加载大量数据。 + +```mermaid +flowchart TD +Start([开始]) --> UseIService["使用IService通用方法"] +UseIService --> ComplexQuery{"复杂查询?"} +ComplexQuery --> |是| UseXML["使用XML映射文件"] +ComplexQuery --> |否| UseAnnotation["使用@Select注解"] +UseXML --> BuildQuery["构建动态查询条件"] +UseAnnotation --> BuildQuery +BuildQuery --> UseQueryWrapper["使用QueryWrapper"] +UseQueryWrapper --> UsePagination["使用分页插件"] +UsePagination --> End([结束]) +``` + +**Section sources** +- [JobMapper.java](file://datavines-server/src/main/java/io/datavines/server/repository/mapper/JobMapper.java#L31-L51) +- [JobMapper.xml](file://datavines-server/src/main/resources/mapper/JobMapper.xml#L27-L66) + +## 事务管理与异常处理 + +### 事务管理 +datavines-server模块使用Spring的声明式事务管理,通过@Transactional注解来控制事务的边界。例如,JobServiceImpl类中的create、update、deleteById等方法都使用了@Transactional注解,确保这些操作在同一个事务中执行。 + +```java +@Override +@Transactional(rollbackFor = Exception.class) +public long create(JobCreate jobCreate) throws DataVinesServerException { + // 业务逻辑 +} +``` + +### 异常处理 +异常处理机制通过@RestControllerAdvice和@ExceptionHandler注解实现。DataVinesExceptionHandler类定义了多个异常处理器,用于处理不同类型的异常。 + +```java +@Slf4j +@RestControllerAdvice +public class DataVinesExceptionHandler { + + @ExceptionHandler(DataVinesServerException.class) + public ResponseEntity dataVinesServerExceptionHandler(DataVinesServerException e, HttpServletRequest request) { + log.error("DataVinesServerException:", e); + ResultMap resultMap = new ResultMap(tokenManager); + Status status = e.getStatus(); + if (Status.INVALID_TOKEN.equals(status)){ + return ResponseEntity.ok(new ResultMap().fail(Status.PLEASE_LOGIN.getCode()).message(Status.PLEASE_LOGIN.getMsg())); + } + + if (Status.TOKEN_IS_NULL_ERROR.equals(status)){ + return ResponseEntity.ok(new ResultMap().fail(Status.PLEASE_LOGIN.getCode()).message(Status.PLEASE_LOGIN.getMsg())); + } + + if (!Objects.isNull(status) ) { + resultMap.fail(status.getCode()); + } + resultMap.failAndRefreshToken(request); + resultMap.message(e.getMessage()); + return ResponseEntity.ok(resultMap); + } + + @ExceptionHandler(ConstraintViolationException.class) + public ResponseEntity constraintViolationExceptionHandler(Exception e, HttpServletRequest request) { + log.error("ConstraintViolationException:", e); + ResultMap resultMap = new ResultMap(tokenManager); + resultMap.failAndRefreshToken(request); + resultMap.message(buildValidFailMessage((ConstraintViolationException) e)); + return ResponseEntity.ok(resultMap); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity methodArgumentNotValidExceptionHandler(Exception e, HttpServletRequest request) { + log.error("MethodArgumentNotValidException:", e); + ResultMap resultMap = new ResultMap(tokenManager); + resultMap.failAndRefreshToken(request); + String message = buildValidFailMessage((MethodArgumentNotValidException) e); + resultMap.message(message); + return ResponseEntity.ok(resultMap); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity commonExceptionHandler(Exception e, HttpServletRequest request) { + log.error("Exception:", e); + ResultMap resultMap = new ResultMap(tokenManager); + resultMap.failAndRefreshToken(request); + resultMap.message(e.getMessage()); + return ResponseEntity.ok(resultMap); + } +} +``` + +**Section sources** +- [JobServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobServiceImpl.java#L129) +- [DataVinesExceptionHandler.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java#L48-L95) + +## 领域模型与数据库映射 + +### 领域模型 +领域模型通过实体类来表示,每个实体类对应数据库中的一张表。例如,Job实体类对应dv_job表,使用@Table注解指定表名。 + +```java +@Data +@TableName("dv_job") +public class Job implements Serializable { + + private static final long serialVersionUID = -1L; + + @TableId(type = IdType.AUTO) + private Long id; + + @TableField(value = "name") + private String name; + + @TableField(value = "type") + private JobType type; + + @TableField(value = "datasource_id") + private Long dataSourceId; + + @TableField(value = "datasource_id_2") + private Long dataSourceId2; + + @TableField(value = "schema_name") + private String schemaName; + + @TableField(value = "table_name") + private String tableName; + + @TableField(value = "column_name") + private String columnName; + + @TableField(value = "selected_column") + private String selectedColumn; + + @TableField(value = "metric_type") + private String metricType; + + @TableField(value = "execute_platform_type") + private String executePlatformType; + + @TableField(value = "execute_platform_parameter",updateStrategy = FieldStrategy.IGNORED) + private String executePlatformParameter; + + @TableField(value = "engine_type") + private String engineType; + + @TableField(value = "engine_parameter",updateStrategy = FieldStrategy.IGNORED) + private String engineParameter; + + @TableField(value = "error_data_storage_id",updateStrategy = FieldStrategy.IGNORED) + private Long errorDataStorageId; + + @TableField(value = "error_data_output_to_datasource_database") + private String errorDataOutputToDataSourceDatabase; + + @TableField(value = "is_error_data_output_to_datasource") + private Boolean isErrorDataOutputToDataSource; + + @TableField(value = "parameter") + private String parameter; + + @TableField(value = "retry_times") + private Integer retryTimes; + + @TableField(value = "retry_interval") + private Integer retryInterval; + + @TableField(value = "timeout") + private Integer timeout; + + @TableField(value = "timeout_strategy") + private TimeoutStrategy timeoutStrategy; + + @TableField(value = "pre_sql") + private String preSql; + + @TableField(value = "post_sql") + private String postSql; + + @TableField(value = "tenant_code",updateStrategy = FieldStrategy.IGNORED) + private Long tenantCode; + + @TableField(value = "env",updateStrategy = FieldStrategy.IGNORED) + private Long env; + + @TableField(value = "create_by") + private Long createBy; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @TableField(value = "create_time") + private LocalDateTime createTime; + + @TableField(value = "update_by") + private Long updateBy; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @TableField(value = "update_time") + private LocalDateTime updateTime; +} +``` + +### 数据库映射 +MyBatis Plus通过注解实现了领域模型与数据库表的映射。@TableName注解指定表名,@TableId注解指定主键字段,@TableField注解指定普通字段。updateStrategy属性用于控制更新策略,例如FieldStrategy.IGNORED表示忽略空值。 + +**Section sources** +- [Job.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java#L28-L125) + +## 性能优化建议 + +### 缓存策略 +对于频繁查询但不经常变化的数据,可以使用缓存来提高性能。例如,可以缓存数据源配置、任务模板等信息。 + +### 批量操作 +对于大量数据的插入、更新或删除操作,应使用批量操作来减少数据库交互次数。MyBatis Plus提供了saveBatch、updateBatchById等方法来支持批量操作。 + +### 查询优化 +1. 使用索引:为经常用于查询条件的字段创建索引。 +2. 分页查询:避免一次性加载大量数据,使用分页插件进行分页查询。 +3. 减少JOIN操作:尽量减少多表JOIN操作,可以通过缓存或预计算来避免复杂的JOIN查询。 + +```mermaid +flowchart TD +Start([开始]) --> UseIndex["使用索引"] +UseIndex --> UsePagination["使用分页查询"] +UsePagination --> ReduceJoin["减少JOIN操作"] +ReduceJoin --> UseCache["使用缓存"] +UseCache --> UseBatch["使用批量操作"] +UseBatch --> End([结束]) +``` + +## 并发问题与解决方案 + +### 并发问题 +在高并发场景下,可能会出现以下问题: +1. 数据竞争:多个线程同时修改同一数据,导致数据不一致。 +2. 死锁:多个事务相互等待对方释放锁,导致系统挂起。 +3. 脏读:一个事务读取了另一个未提交事务的数据。 + +### 解决方案 +1. 使用乐观锁:通过版本号或时间戳来实现乐观锁,避免数据竞争。 +2. 合理设计事务:尽量减少事务的范围和持续时间,避免长时间持有锁。 +3. 使用数据库锁:在必要时使用数据库的行级锁或表级锁来保证数据一致性。 + +```mermaid +flowchart TD +Start([开始]) --> IdentifyProblem["识别并发问题"] +IdentifyProblem --> DataRace{"数据竞争?"} +DataRace --> |是| UseOptimisticLock["使用乐观锁"] +DataRace --> |否| Deadlock{"死锁?"} +Deadlock --> |是| DesignTransaction["合理设计事务"] +Deadlock --> |否| DirtyRead{"脏读?"} +DirtyRead --> |是| UseDatabaseLock["使用数据库锁"] +DirtyRead --> |否| End([结束]) +UseOptimisticLock --> End +DesignTransaction --> End +UseDatabaseLock --> End +``` + +## 总结 +datavines-server模块的服务层设计合理,采用了接口与实现分离的设计模式,使用MyBatis Plus简化了数据库操作,通过Spring的声明式事务管理和异常处理机制保证了系统的稳定性和可靠性。领域模型与数据库表的映射清晰,通过注解实现了自动映射。在性能优化方面,建议使用缓存、批量操作和查询优化来提高系统性能。在并发场景下,应使用乐观锁、合理设计事务和数据库锁来解决并发问题。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\350\260\203\345\272\246\346\234\215\345\212\241\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\350\260\203\345\272\246\346\234\215\345\212\241\345\256\236\347\216\260.md" new file mode 100644 index 00000000..8ff7c84c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\234\215\345\212\241\345\261\202\345\256\236\347\216\260/\350\260\203\345\272\246\346\234\215\345\212\241\345\256\236\347\216\260.md" @@ -0,0 +1,373 @@ +# 调度服务实现 + + +**本文档引用的文件** +- [JobScheduleService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobScheduleService.java) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [JobSchedule.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobSchedule.java) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java) +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [JobScheduleType.java](file://datavines-server\src\main\java\io\datavines\server\enums\JobScheduleType.java) +- [FunCron.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\FunCron.java) +- [StrategyFactory.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\StrategyFactory.java) +- [DayCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\DayCronImpl.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [架构概述](#架构概述) +4. [详细组件分析](#详细组件分析) +5. [调度流程分析](#调度流程分析) +6. [Cron表达式处理机制](#cron表达式处理机制) +7. [调度状态管理](#调度状态管理) +8. [高并发场景优化建议](#高并发场景优化建议) + +## 简介 +本文档详细解析基于Quartz的作业调度系统实现,涵盖定时任务的创建、暂停、恢复和删除操作。文档深入阐述了Cron表达式验证、调度状态管理和触发器配置的业务逻辑,以及JobScheduleServiceImpl如何与Quartz调度器交互。同时描述了调度任务与作业实例的映射关系,以及调度失败的重试机制和告警通知集成。 + +## 核心组件 + +JobScheduleService服务是DataVines平台中负责管理数据质量检查任务调度的核心组件。该服务基于Quartz调度框架实现,提供了完整的定时任务管理功能,包括任务的创建、更新、删除和状态管理。服务通过JobSchedule实体与数据库交互,存储调度配置信息,并通过QuartzExecutors与底层调度引擎通信。 + +**本文档引用的文件** +- [JobScheduleService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobScheduleService.java) +- [JobSchedule.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobSchedule.java) + +## 架构概述 + +```mermaid +graph TB +subgraph "调度服务层" +JobScheduleService[JobScheduleService] +JobScheduleServiceImpl[JobScheduleServiceImpl] +end +subgraph "调度执行层" +QuartzExecutors[QuartzExecutors] +Scheduler[Quartz Scheduler] +end +subgraph "数据层" +JobScheduleMapper[JobScheduleMapper] +JobMapper[JobMapper] +Database[(数据库)] +end +subgraph "调度任务" +DataQualityScheduleJob[DataQualityScheduleJob] +ScheduleJobInfo[ScheduleJobInfo] +end +JobScheduleService --> JobScheduleServiceImpl +JobScheduleServiceImpl --> QuartzExecutors +JobScheduleServiceImpl --> JobScheduleMapper +JobScheduleServiceImpl --> JobMapper +JobScheduleMapper --> Database +JobMapper --> Database +QuartzExecutors --> Scheduler +QuartzExecutors --> ScheduleJobInfo +ScheduleJobInfo --> DataQualityScheduleJob +``` + +**图示来源** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java) + +## 详细组件分析 + +### JobScheduleService 分析 + +JobScheduleService接口定义了调度服务的核心操作,包括创建、更新、删除调度任务以及获取调度信息。服务通过JobSchedule实体类与数据库交互,存储调度配置的详细信息。 + +```mermaid +classDiagram +class JobScheduleService { ++createOrUpdate(JobScheduleCreateOrUpdate) JobSchedule ++deleteById(long) int ++deleteBySchedule(JobSchedule) int ++getById(long) JobSchedule ++getByJobId(Long) JobSchedule ++getCron(MapParam) String[] ++listFutureCronRunTimes(String) String[] +} +class JobSchedule { +-Long id +-Long jobId +-String type +-String param +-String cronExpression +-boolean status +-LocalDateTime startTime +-LocalDateTime endTime +-Long createBy +-LocalDateTime createTime +-Long updateBy +-LocalDateTime updateTime +} +JobScheduleService <|-- JobScheduleServiceImpl +JobScheduleServiceImpl --> JobSchedule +JobScheduleServiceImpl --> QuartzExecutors +JobScheduleServiceImpl --> JobMapper +``` + +**图示来源** +- [JobScheduleService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobScheduleService.java) +- [JobSchedule.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobSchedule.java) + +**本文档引用的文件** +- [JobScheduleService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\JobScheduleService.java) +- [JobSchedule.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobSchedule.java) + +### QuartzExecutors 分析 + +QuartzExecutors是Quartz调度器的封装类,负责与底层调度引擎交互。它提供了添加、删除和查询调度任务的功能,并处理了时区转换等复杂逻辑。 + +```mermaid +classDiagram +class QuartzExecutors { +-Scheduler scheduler +-ReadWriteLock lock ++addJob(Class~Job~, ScheduleJobInfo) void ++deleteJob(ScheduleJobInfo) boolean ++deleteAllJobs(Scheduler, String) boolean ++isValid(String) boolean ++listFutureCronRunTimes(String, Integer) String[] +-buildJobName(ScheduleJobInfo) String +-buildJobGroupName(ScheduleJobInfo) String +-buildDataMap(ScheduleJobInfo) Map~String, Object~ +-buildDate(LocalDateTime) Date +} +class ScheduleJobInfo { +-ScheduleJobType type +-CommonTaskType taskType +-Long datasourceId +-Long id +-String cronExpression +-LocalDateTime startTime +-LocalDateTime endTime +} +QuartzExecutors --> ScheduleJobInfo +QuartzExecutors --> Scheduler +``` + +**图示来源** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java) + +**本文档引用的文件** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [ScheduleJobInfo.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\ScheduleJobInfo.java) + +## 调度流程分析 + +### 调度任务创建流程 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Service as "JobScheduleServiceImpl" +participant Quartz as "QuartzExecutors" +participant DB as "数据库" +Client->>Service : createOrUpdate(JobScheduleCreateOrUpdate) +alt 创建新调度 +Service->>Service : validateJobSchedule(jobScheduleCreate) +Service->>DB : check if schedule exists +DB-->>Service : false +Service->>Service : prepareJobSchedule(jobScheduleCreate) +Service->>Quartz : addJob(DataQualityScheduleJob, scheduleJobInfo) +Quartz->>Quartz : buildJobName/scheduleJobInfo +Quartz->>Quartz : buildDataMap(scheduleJobInfo) +Quartz->>Quartz : create JobDetail and Trigger +Quartz-->>Service : success +Service->>DB : insert JobSchedule +DB-->>Service : success +Service-->>Client : JobSchedule +end +alt 更新现有调度 +Service->>Service : getExistingSchedule(id) +Service->>Quartz : deleteJob(scheduleJobInfo) +Service->>Quartz : addJob(DataQualityScheduleJob, scheduleJobInfo) +Service->>DB : update JobSchedule +DB-->>Service : success +Service-->>Client : JobSchedule +end +``` + +**图示来源** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) + +**本文档引用的文件** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) + +### 调度任务执行流程 + +```mermaid +sequenceDiagram +participant Quartz as "Quartz Scheduler" +participant Job as "DataQualityScheduleJob" +participant Service as "JobExternalService" +participant JobService as "JobService" +Quartz->>Job : execute(JobExecutionContext) +Job->>Job : extract jobId from JobDataMap +Job->>Job : calculate scheduleTime and fireTime +Job->>Service : getJobById(jobId) +Service-->>Job : Job object +alt Job exists +Job->>JobService : execute(jobId, scheduleTime) +JobService-->>Job : execution result +Job-->>Quartz : success +else Job not found +Job->>Job : log warning +Job-->>Quartz : complete +end +``` + +**图示来源** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) +- [JobExternalService.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobExternalService.java) + +**本文档引用的文件** +- [DataQualityScheduleJob.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\DataQualityScheduleJob.java) + +## Cron表达式处理机制 + +### Cron表达式生成策略 + +```mermaid +classDiagram +class FunCron { ++funcDeal(String) String ++getFuncName() String +} +class StrategyFactory { +-Map~String, FunCron~ services ++getByType(String) FunCron ++register(String, FunCron) void +} +class DayCronImpl { ++funcDeal(String) String ++getFuncName() String ++afterPropertiesSet() void +} +class HourCronImpl { ++funcDeal(String) String ++getFuncName() String ++afterPropertiesSet() void +} +class WeekCronImpl { ++funcDeal(String) String ++getFuncName() String ++afterPropertiesSet() void +} +class MonthCronImpl { ++funcDeal(String) String ++getFuncName() String ++afterPropertiesSet() void +} +FunCron <|.. DayCronImpl +FunCron <|.. HourCronImpl +FunCron <|.. WeekCronImpl +FunCron <|.. MonthCronImpl +StrategyFactory --> FunCron +JobScheduleServiceImpl --> StrategyFactory +``` + +**图示来源** +- [FunCron.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\FunCron.java) +- [StrategyFactory.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\StrategyFactory.java) +- [DayCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\DayCronImpl.java) + +**本文档引用的文件** +- [FunCron.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\FunCron.java) +- [StrategyFactory.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\StrategyFactory.java) +- [DayCronImpl.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\cron\impl\DayCronImpl.java) + +### Cron表达式处理流程 + +```mermaid +flowchart TD +Start([开始]) --> ValidateInput["验证输入参数"] +ValidateInput --> InputValid{"参数有效?"} +InputValid --> |否| ReturnError["返回参数错误"] +InputValid --> |是| CheckScheduleType["检查调度类型"] +CheckScheduleType --> ScheduleType{"类型: cycle/crontab?"} +ScheduleType --> |cycle| ProcessCycle["处理周期调度"] +ScheduleType --> |crontab| ProcessCrontab["处理Crontab调度"] +ProcessCycle --> GetCycleType["获取周期类型(day/hour/week/month)"] +GetCycleType --> GetStrategy["从StrategyFactory获取FunCron策略"] +GetStrategy --> ExecuteStrategy["执行funcDeal生成Cron表达式"] +ExecuteStrategy --> StoreCron["存储Cron表达式到JobSchedule"] +ProcessCrontab --> ValidateCron["验证Cron表达式有效性"] +ValidateCron --> CronValid{"Cron有效?"} +CronValid --> |否| ReturnCronError["返回Cron格式错误"] +CronValid --> |是| StoreCron +StoreCron --> SaveToDB["保存到数据库"] +SaveToDB --> RegisterQuartz["注册到Quartz调度器"] +RegisterQuartz --> End([完成]) +ReturnError --> End +ReturnCronError --> End +``` + +**图示来源** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) + +**本文档引用的文件** +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) + +## 调度状态管理 + +### 调度状态转换 + +```mermaid +stateDiagram-v2 +[*] --> Idle +Idle --> Creating : "创建调度" +Creating --> Active : "成功创建" +Creating --> Error : "创建失败" +Active --> Updating : "更新调度" +Updating --> Active : "更新成功" +Updating --> Error : "更新失败" +Active --> Deleting : "删除调度" +Deleting --> Idle : "删除成功" +Deleting --> Error : "删除失败" +Error --> Idle : "重置" +note right of Active +状态 : 启用 +可执行 +定时触发 +end note +note right of Idle +状态 : 禁用 +不执行 +可重新启用 +end note +``` + +**图示来源** +- [JobSchedule.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobSchedule.java) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) + +**本文档引用的文件** +- [JobSchedule.java](file://datavines-server\src\main\java\io\datavines\server\repository\entity\JobSchedule.java) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) + +## 高并发场景优化建议 + +### 集群部署与分布式锁 + +在高并发场景下,为确保调度服务的稳定性和可靠性,建议采用以下优化策略: + +1. **集群部署**:将调度服务部署在多个节点上,通过负载均衡分发请求,提高系统的可用性和容错能力。 +2. **分布式锁**:使用Redis或Zookeeper实现分布式锁,确保在集群环境下同一调度任务不会被重复执行。 +3. **任务分片策略**:对于大规模数据处理任务,采用任务分片策略,将大任务拆分为多个小任务并行执行,提高处理效率。 +4. **数据库连接池优化**:配置合理的数据库连接池参数,避免因连接数过多导致数据库性能下降。 +5. **Quartz集群模式**:启用Quartz的集群模式,通过数据库表实现节点间的协调,确保任务在集群中只执行一次。 + +这些优化策略可以有效提升调度服务在高并发场景下的性能和稳定性,确保数据质量检查任务能够按时准确执行。 + +**本文档引用的文件** +- [QuartzExecutors.java](file://datavines-server\src\main\java\io\datavines\server\dqc\coordinator\quartz\QuartzExecutors.java) +- [JobScheduleServiceImpl.java](file://datavines-server\src\main\java\io\datavines\server\repository\service\impl\JobScheduleServiceImpl.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\236\266\346\236\204\350\256\276\350\256\241.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\236\266\346\236\204\350\256\276\350\256\241.md" new file mode 100644 index 00000000..21829c3f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\346\236\266\346\236\204\350\256\276\350\256\241.md" @@ -0,0 +1,400 @@ +# 架构设计 + + +**本文档引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [JacksonConfig.java](file://datavines-server/src/main/java/io/datavines/server/config/JacksonConfig.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [MybatisPlusConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/MybatisPlusConfig.java) +- [SpringApplicationContext.java](file://datavines-server/src/main/java/io/datavines/server/utils/SpringApplicationContext.java) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java) +- [CommonTaskScheduler.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java) + + +## 目录 +1. [引言](#引言) +2. [技术栈与分层架构](#技术栈与分层架构) +3. [应用启动流程](#应用启动流程) +4. [核心配置文件分析](#核心配置文件分析) +5. [组件扫描与配置加载机制](#组件扫描与配置加载机制) +6. [序列化与API文档配置](#序列化与api文档配置) +7. [数据访问与持久化配置](#数据访问与持久化配置) +8. [系统上下文与组件交互](#系统上下文与组件交互) +9. [性能调优建议](#性能调优建议) +10. [常见配置问题解决方案](#常见配置问题解决方案) + +## 引言 + +DataVines Server 是一个基于 Spring Boot 构建的微服务应用,作为数据质量监控平台的核心服务组件,负责处理数据质量检查、任务调度、元数据管理等核心功能。该服务采用典型的分层架构设计,通过 Spring Boot 的自动配置和依赖注入机制,实现了与数据库、执行引擎和注册中心的集成。本文档详细阐述了 datavines-server 模块的架构设计,包括应用的启动流程、配置加载机制、核心配置项以及与外部系统的集成方式。 + +## 技术栈与分层架构 + +datavines-server 模块构建于成熟的 Java 技术栈之上,采用标准的 Controller-Service-Mapper 分层架构模式,确保了代码的清晰性和可维护性。 + +**技术栈**: +- **核心框架**: Spring Boot 2.x +- **Web 服务器**: Jetty (替代默认的 Tomcat) +- **数据库连接池**: HikariCP +- **ORM 框架**: MyBatis Plus +- **任务调度**: Quartz +- **API 文档**: Swagger (Springfox) +- **注册中心**: 支持 MySQL 和 ZooKeeper +- **日志框架**: Logback +- **JSON 处理**: Jackson + +**分层架构与各层职责**: +- **Controller 层**: 位于 `io.datavines.server.api.controller` 包下,负责接收 HTTP 请求,进行参数校验和基本的数据转换,然后调用 Service 层处理业务逻辑。该层通过 `@RestController` 和 `@RequestMapping` 等注解暴露 RESTful API。 +- **Service 层**: 位于 `io.datavines.server.repository.service` 包下,是业务逻辑的核心。它封装了具体的业务规则和流程,协调多个 Mapper 操作,并处理事务。Service 层为 Controller 层提供粗粒度的服务接口。 +- **Mapper 层**: 位于 `io.datavines.server.repository.mapper` 包下,是数据访问层。它通过 MyBatis Plus 的 Mapper 接口与数据库进行交互,执行 CRUD 操作。该层直接与数据库表映射,屏蔽了底层 SQL 的复杂性。 + +这种分层架构实现了关注点分离,使得各层职责明确,便于团队协作开发和单元测试。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L48-L50) +- [pom.xml](file://datavines-server/pom.xml#L35-L589) + +## 应用启动流程 + +datavines-server 的启动流程由 `DataVinesServer` 主类驱动,遵循 Spring Boot 的生命周期,并在此基础上扩展了自定义的初始化逻辑。 + +1. **JVM 启动**: JVM 执行 `DataVinesServer` 类的 `main` 方法。 +2. **Spring Boot 启动**: 调用 `SpringApplication.run(DataVinesServer.class)`,触发 Spring Boot 的自动配置过程。Spring 容器开始扫描带有 `@SpringBootApplication` 注解的类及其 `scanBasePackages` 指定的包(`io.datavines`)下的所有组件。 +3. **组件注入**: Spring 容器创建并管理所有被 `@Component`, `@Service`, `@Repository`, `@Controller` 等注解标记的 Bean,包括 `SpringApplicationContext`, `Environment`, `RegistryHolder` 等。 +4. **执行初始化方法**: 当所有必需的 Bean 都被注入后,Spring 容器会回调被 `@PostConstruct` 注解标记的方法 `initializeAndStart()`。 +5. **自定义初始化**: + - **初始化公共属性**: `initCommonProperties()` 方法从 Spring 的 `DataSource` 中读取数据库连接信息(URL, 用户名, 密码, 驱动),并将其存入 `CommonPropertyUtils` 的静态配置中,供后续模块使用。 + - **启动核心管理器**: 创建并启动 `JobExecuteManager` 和 `CommonTaskManager`,它们负责管理作业执行和通用任务。 + - **初始化注册中心**: 使用 `PluginLoader` SPI 机制,根据配置动态加载并初始化注册中心实现(如 MySQL 或 ZooKeeper)。 + - **启动注册服务**: 创建 `Register` 实例并调用其 `start()` 方法,向注册中心注册本服务实例,并开始监听集群事件(如节点上下线)。 + - **启动调度器**: 启动 `JobScheduler` 和 `CommonTaskScheduler`,使系统具备调度和执行数据质量检查作业的能力。 +6. **注册关闭钩子**: 通过 `Runtime.getRuntime().addShutdownHook()` 注册一个 JVM 关闭钩子,确保在服务优雅关闭时,能够正确释放数据库连接、关闭注册中心会话等资源。 + +这个流程确保了服务在完全初始化后才开始提供服务,并且在关闭时能够清理资源,避免数据丢失或连接泄漏。 + +```mermaid +sequenceDiagram +participant JVM +participant SpringApplication +participant DataVinesServer +participant SpringContext +participant Initialize +JVM->>SpringApplication : main() +SpringApplication->>DataVinesServer : run() +DataVinesServer->>SpringContext : 创建容器,扫描组件 +SpringContext->>DataVinesServer : 注入 @Autowired 依赖 +DataVinesServer->>Initialize : @PostConstruct initializeAndStart() +Initialize->>Initialize : initCommonProperties() +Initialize->>Initialize : 启动 JobExecuteManager +Initialize->>Initialize : 启动 CommonTaskManager +Initialize->>PluginLoader : 加载注册中心插件 +PluginLoader-->>Initialize : 返回 Registry 实例 +Initialize->>Registry : registry.init() +Initialize->>Register : register.start() +Initialize->>JobScheduler : jobScheduler.start() +Initialize->>CommonTaskScheduler : commonTaskScheduler.start() +Initialize->>JVM : 注册关闭钩子 +DataVinesServer-->>SpringApplication : 启动完成 +``` + +**Diagram sources ** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L69-L110) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L141-L157) + +## 核心配置文件分析 + +`application.yaml` 是 datavines-server 的核心配置文件,定义了应用运行所需的各种参数。 + +```yaml +spring: + main: + banner-mode: off + allow-circular-references: true + application: + name: datavines-server + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://127.0.0.1:5432/datavines + username: postgres + password: 123456 + hikari: + connection-test-query: select 1 + minimum-idle: 5 + auto-commit: true + validation-timeout: 3000 + pool-name: datavines + maximum-pool-size: 50 + connection-timeout: 30000 + idle-timeout: 600000 + leak-detection-threshold: 0 + initialization-fail-timeout: 1 + quartz: + job-store-type: jdbc + jdbc: + initialize-schema: never + properties: + org.quartz.threadPool.threadPriority: 5 + org.quartz.jobStore.isClustered: true + org.quartz.jobStore.class: org.springframework.scheduling.quartz.LocalDataSourceJobStore + org.quartz.scheduler.instanceId: AUTO + org.quartz.jobStore.tablePrefix: QRTZ_ + org.quartz.jobStore.acquireTriggersWithinLock: true + org.quartz.scheduler.instanceName: datavines + org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool + org.quartz.jobStore.useProperties: false + org.quartz.threadPool.makeThreadsDaemons: true + org.quartz.threadPool.threadCount: 25 + org.quartz.jobStore.misfireThreshold: 60000 + org.quartz.scheduler.batchTriggerAcquisitionMaxCount: 1 + org.quartz.scheduler.makeSchedulerThreadDaemon: true + org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate + org.quartz.jobStore.clusterCheckinInterval: 5000 + mvc: + pathmatch: + matching-strategy: ant_path_matcher + +mybatis-plus: + type-enums-package: io.datavines.*.enums + +server: + port: 5600 + +management: + endpoints: + web: + exposure: + include: '*' + metrics: + tags: + application: ${spring.application.name} + +logging: + config: classpath:server-logback.xml +--- +spring: + config: + activate: + on-profile: mysql + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/datavines?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: 123456 + quartz: + properties: + org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate +``` + +**关键配置项说明**: +- **`spring.application.name`**: 定义了应用的名称,用于服务发现和监控。 +- **`spring.datasource`**: 配置了主数据源,用于存储应用的元数据和状态信息。默认使用 PostgreSQL,通过 `---` 分隔符定义了 `mysql` 配置文件,可通过激活 profile 切换数据库。 +- **`spring.datasource.hikari`**: HikariCP 连接池的详细配置。`maximum-pool-size: 50` 设置了最大连接数,`idle-timeout: 600000` (10分钟) 定义了连接在池中空闲的最长时间。 +- **`server.port`**: 指定了应用监听的端口号,这里是 5600。 +- **`spring.quartz`**: 配置了 Quartz 调度框架。`job-store-type: jdbc` 表明使用数据库作为任务存储,`org.quartz.jobStore.isClustered: true` 启用了集群模式,允许多个 datavines-server 实例协同工作。`threadCount: 25` 设置了调度线程池的大小。 +- **`management.endpoints.web.exposure.include: '*'`**: 开启了所有 Spring Boot Actuator 端点,便于监控应用的健康状况、指标等。 +- **`logging.config`**: 指定了日志配置文件 `server-logback.xml` 的位置。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) + +## 组件扫描与配置加载机制 + +datavines-server 的组件扫描和配置加载机制是其模块化和可扩展性的基础。 + +**组件扫描**: +组件扫描由 `@SpringBootApplication` 注解驱动。该注解是一个组合注解,包含了 `@ComponentScan`。在 `DataVinesServer` 类上,`@SpringBootApplication` 显式指定了 `scanBasePackages = {"io.datavines"}`。这意味着 Spring 容器在启动时,会自动扫描 `io.datavines` 包及其所有子包下的类,寻找带有 `@Component`, `@Service`, `@Repository`, `@Controller` 等注解的类,并将它们注册为 Spring Bean。例如,`LoginController`、`JobService` 和 `JobMapper` 都会被自动发现和管理。 + +**配置加载机制**: +配置加载是一个多层级的过程: +1. **外部配置文件**: `application.yaml` 是主要的配置来源。Spring Boot 会按特定顺序(如命令行参数、`application.yaml`、环境变量等)加载配置,并将它们注入到带有 `@Value` 或通过 `Environment` 对象访问的 Bean 中。 +2. **运行时动态配置**: 除了静态的 `application.yaml`,系统还支持运行时动态更新配置。`Register` 类在启动时会从数据库的 `config` 表中加载所有配置项 (`configService.listConfig()`),并使用 `CommonPropertyUtils.setValue()` 将这些配置注入到全局的静态配置中。这使得管理员可以在不重启服务的情况下,通过管理界面修改某些运行时参数。 +3. **SPI 扩展机制**: 对于注册中心等可插拔的组件,系统使用了自研的 SPI (Service Provider Interface) 机制。`PluginLoader` 类负责根据配置的类型(如 `registry.type=mysql`)去查找并加载对应的实现类(如 `datavines-registry-mysql` 模块中的实现)。这实现了核心逻辑与具体实现的解耦。 + +这种机制结合了 Spring Boot 的自动配置能力和自定义的动态配置,提供了极大的灵活性。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L48-L50) +- [Register.java](file://datavines-server/src/main/java/io/datavines/server/registry/Register.java#L78-L85) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +## 序列化与API文档配置 + +### Jackson 序列化配置 + +为了确保在前后端交互中大数值的精度不丢失,datavines-server 配置了特定的 Jackson 序列化规则。 + +`JacksonConfig` 类通过 `@Configuration` 注解定义了一个配置类,并提供了一个名为 `jacksonLongToString` 的 `Bean`。该 Bean 是一个 `Jackson2ObjectMapperBuilderCustomizer`,它会定制 Spring Boot 创建的 `ObjectMapper`。其核心作用是将 `Long`, `long`, `BigInteger`, `BigDecimal` 等大数值类型序列化为 JSON 字符串,而不是数字。这是因为 JavaScript 的 Number 类型有精度限制,当处理超过其安全整数范围(`Number.MAX_SAFE_INTEGER`)的长整型时,可能会发生精度丢失。通过序列化为字符串,前端可以安全地处理这些大数值。 + +```java +@Bean +public Jackson2ObjectMapperBuilderCustomizer jacksonLongToString() { + return builder -> { + builder.serializerByType(Long.class, ToStringSerializer.instance); + builder.serializerByType(long.class, ToStringSerializer.instance); + builder.serializerByType(BigInteger.class, ToStringSerializer.instance); + builder.serializerByType(BigDecimal.class, ToStringSerializer.instance); + }; +} +``` + +**Section sources** +- [JacksonConfig.java](file://datavines-server/src/main/java/io/datavines/server/config/JacksonConfig.java#L27-L44) + +### Swagger API 文档集成 + +datavines-server 集成了 Swagger (通过 Springfox) 来自动生成和提供 RESTful API 文档。 + +`DataVinesSwaggerConfig` 类是一个配置类,它创建了一个 `Docket` Bean。这个 `Docket` Bean 定义了 Swagger 文档的生成规则: +- **`DocumentationType.SWAGGER_2`**: 指定使用 Swagger 2.0 规范。 +- **`apis(RequestHandlerSelectors.basePackage("io.datavines.server.api.controller"))`**: 指定只扫描 `io.datavines.server.api.controller` 包下的控制器来生成 API 文档。 +- **`securitySchemes` 和 `securityContexts`**: 配置了基于 `Authorization` 头的 API 密钥认证,允许在 Swagger UI 中方便地进行需要认证的 API 调用测试。 +- **`apiInfo()`**: 定义了文档的元信息,如标题 "DataVines Api Docs"。 + +集成后,可以通过访问 `/swagger-ui.html` 路径来查看和测试所有公开的 API。 + +**Section sources** +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java#L38-L72) + +### Web MVC 配置 + +`WebMvcConfig` 类实现了 `WebMvcConfigurer` 接口,用于自定义 Spring MVC 的行为。 + +该配置类主要做了以下几件事: +1. **注册拦截器**: 通过 `addInterceptors` 方法注册了 `AuthenticationInterceptor` 拦截器。该拦截器对所有以 `/api/` 开头的请求路径进行认证检查,但排除了 `/api/login` 路径,确保登录接口可以匿名访问。 +2. **配置静态资源**: 通过 `addResourceHandlers` 方法,将 Swagger UI 的静态资源(如 `swagger-ui.html` 和 `/webjars/**`)以及应用自身的静态资源(如前端页面)映射到正确的类路径位置。 +3. **配置视图控制器**: 通过 `addViewControllers` 方法,将根路径 `/` 直接映射到 `index.html`,这是单页应用(SPA)的常见做法。 +4. **配置跨域 (CORS)**: 通过 `corsFilter` Bean 配置了全局的 CORS 策略,允许所有来源 (`*`) 访问,允许所有头和方法,并支持凭据(如 Cookie),这对于前后端分离的架构至关重要。 +5. **配置国际化**: 通过 `localeResolver` Bean 配置了基于 Cookie 的区域解析器,支持多语言。 + +```java +@Override +public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(loginRequiredInterceptor()) + .addPathPatterns(DataVinesConstants.BASE_API_PATH + "/**") + .excludePathPatterns(DataVinesConstants.BASE_API_PATH + "/login"); +} +``` + +**Section sources** +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java#L35-L100) + +## 数据访问与持久化配置 + +### MyBatis Plus 配置 + +datavines-server 使用 MyBatis Plus 作为 ORM 框架,简化了数据库操作。 + +`MybatisPlusConfig` 配置类通过 `@Configuration` 注解定义,并提供了一个 `MybatisPlusInterceptor` Bean。该拦截器是 MyBatis Plus 的核心,用于添加各种功能插件。 + +目前,该配置主要添加了分页插件 `PaginationInnerInterceptor`,并指定了数据库类型为 `DbType.MYSQL`。虽然主数据源默认是 PostgreSQL,但分页插件的 SQL 生成逻辑可能依赖于此配置。MyBatis Plus 的分页插件可以自动将内存分页转换为数据库的 `LIMIT` 语句,极大地简化了分页查询的代码。 + +```java +@Bean +public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; +} +``` + +**Section sources** +- [MybatisPlusConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/MybatisPlusConfig.java#L25-L34) + +### 数据库集成 + +datavines-server 通过 Spring Boot 的 `spring.datasource` 配置与关系型数据库(PostgreSQL/MySQL)集成。应用启动时,Spring Boot 会自动配置一个 `DataSource` Bean(默认是 HikariCP),并将其注入到 `SqlSessionFactory` 中,从而完成 MyBatis Plus 的初始化。 + +此外,系统还通过 `datavines-common` 模块中的 `JdbcDataSourceManager` 管理用户数据源的连接。当需要连接用户的数据库(如 MySQL, Oracle)来执行数据质量检查时,`JdbcDataSourceManager` 会根据用户提供的连接信息,创建并缓存一个独立的 HikariCP 连接池,以保证连接的安全和高效复用。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L23-L39) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java#L84-L143) + +## 系统上下文与组件交互 + +### 系统上下文图 + +datavines-server 作为核心服务,与多个外部系统紧密集成。 + +```mermaid +graph TD +subgraph "外部系统" +DB[(关系型数据库
PostgreSQL/MySQL)] +ExecutionEngine[(执行引擎
Spark/Livy)] +Registry[(注册中心
MySQL/ZooKeeper)] +end +subgraph "datavines-server" +Controller[Controller 层] +Service[Service 层] +Mapper[Mapper 层] +Scheduler[Quartz 调度器] +Register[注册服务] +end +Controller --> Service +Service --> Mapper +Service --> Scheduler +Mapper --> DB +Register --> Registry +Scheduler --> ExecutionEngine +``` + +**说明**: +- **数据库 (DB)**: 存储 datavines-server 自身的元数据,如用户信息、作业定义、执行历史等。通过 `spring.datasource` 配置连接。 +- **执行引擎 (ExecutionEngine)**: datavines-server 负责调度作业,但实际的数据质量检查任务是在外部的执行引擎(如 Spark 集群)上运行的。server 通过 `datavines-engine-executor` 模块提交任务。 +- **注册中心 (Registry)**: 用于服务发现和集群协调。当部署多个 datavines-server 实例时,它们通过注册中心感知彼此的存在,实现高可用和故障转移。 + +### 组件交互图 + +以下是 `JobController` 接收一个创建作业请求后,各组件之间的交互流程。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "JobController" +participant Service as "JobService" +participant Mapper as "JobMapper" +participant DB as "数据库" +Client->>Controller : POST /api/job +Controller->>Service : jobService.create(jobCreate) +Service->>Mapper : jobMapper.insert(job) +Mapper->>DB : INSERT INTO job ... +DB-->>Mapper : 返回主键 +Mapper-->>Service : Job 对象 +Service-->>Controller : 创建结果 +Controller-->>Client : 返回成功响应 +``` + +**说明**: +1. 客户端发送创建作业的 HTTP 请求。 +2. `JobController` 接收请求,调用 `JobService` 的 `create` 方法。 +3. `JobService` 处理业务逻辑,调用 `JobMapper` 的 `insert` 方法。 +4. `JobMapper` 执行 SQL 插入语句,将作业信息写入数据库。 +5. 数据库返回插入结果,`JobMapper` 将其封装为 `Job` 对象返回给 `JobService`。 +6. `JobService` 将结果返回给 `JobController`,最终由 `JobController` 返回给客户端。 + +**Diagram sources ** +- [系统上下文图](file://datavines-server/src/main/resources/application.yaml#L23-L27) +- [组件交互图](file://datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java#L47-L48) + +## 性能调优建议 + +1. **数据库连接池调优**: 根据并发量调整 `spring.datasource.hikari.maximum-pool-size`。如果应用日志中频繁出现获取连接超时,应适当增大该值。同时,确保 `idle-timeout` 和 `max-lifetime` 的设置合理,避免连接因长时间空闲被数据库端关闭。 +2. **Quartz 调度线程池**: `org.quartz.threadPool.threadCount` 决定了并发执行的作业数量。如果发现作业调度延迟,可以适当增加线程数,但需考虑执行引擎的负载能力。 +3. **JVM 参数**: 为 JVM 分配足够的堆内存(`-Xms`, `-Xmx`),并选择合适的垃圾回收器(如 G1GC),以减少 GC 停顿时间。 +4. **SQL 优化**: 定期审查慢查询日志,对 `job`, `job_execution` 等大表的关键字段(如 `datasource_id`, `create_time`)建立索引,以加速分页查询。 +5. **缓存**: 对于频繁读取且不常变更的数据(如配置项、枚举值),可以引入 Redis 等缓存,减少数据库压力。 + +## 常见配置问题解决方案 + +1. **问题**: 启动时报错 `Failed to configure a DataSource`。 + **解决方案**: 检查 `application.yaml` 中的 `spring.datasource.url`, `username`, `password` 是否正确。确认数据库服务已启动,并且网络可达。检查 `driver-class-name` 是否与数据库类型匹配。 + +2. **问题**: Swagger UI 无法访问。 + **解决方案**: 确认 `pom.xml` 中已引入 `springfox-boot-starter` 依赖。检查 `DataVinesSwaggerConfig` 类是否被正确扫描。确认访问路径是否为 `/swagger-ui.html`。 + +3. **问题**: 多个 server 实例无法形成集群。 + **解决方案**: 确保所有实例的 `spring.quartz.job-store-type` 都设置为 `jdbc`,并且连接到同一个数据库。检查 `org.quartz.jobStore.isClustered` 是否为 `true`。确认 `registry.type` 配置正确,并且所有实例都能访问注册中心。 + +4. **问题**: 作业执行失败,提示连接用户数据源失败。 + **解决方案**: 检查用户在前端配置的数据源连接信息(JDBC URL, 用户名, 密码)是否正确。确认目标数据库的网络防火墙允许来自 datavines-server 的连接。检查数据库的连接数限制。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\350\256\244\350\257\201\344\270\216\346\235\203\351\231\220.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\350\256\244\350\257\201\344\270\216\346\235\203\351\231\220.md" new file mode 100644 index 00000000..62689457 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-server\346\250\241\345\235\227/\350\256\244\350\257\201\344\270\216\346\235\203\351\231\220.md" @@ -0,0 +1,397 @@ +# 认证与权限 + + +**本文档引用的文件** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [AccessTokenService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/AccessTokenService.java) +- [AccessTokenServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/AccessTokenServiceImpl.java) +- [AccessToken.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/AccessToken.java) +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [UserWorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/UserWorkSpace.java) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) + + +## 目录 +1. [简介](#简介) +2. [基于Token的用户认证机制](#基于token的用户认证机制) +3. [自定义注解实现原理](#自定义注解实现原理) +4. [全局认证拦截器](#全局认证拦截器) +5. [权限控制模型](#权限控制模型) +6. [AccessToken管理与有效期策略](#accesstoken管理与有效期策略) +7. [安全最佳实践](#安全最佳实践) +8. [扩展认证方式集成](#扩展认证方式集成) + +## 简介 + +DataVines系统的认证与权限体系基于JWT(JSON Web Token)实现,提供了一套完整的用户身份验证和访问控制机制。系统通过Token进行用户身份验证,结合自定义注解和拦截器实现灵活的权限控制。该体系支持用户、工作空间和租户的多层级权限管理,确保系统资源的安全访问。 + +## 基于Token的用户认证机制 + +DataVines采用基于JWT的Token认证机制,实现无状态的用户身份验证。认证流程包括登录、Token生成、Token验证和请求认证等环节。 + +### 登录流程 + +用户登录流程如下: +1. 用户通过前端界面提交用户名和密码 +2. 服务器验证用户凭证的合法性 +3. 验证通过后生成JWT Token +4. 将Token返回给客户端 +5. 客户端在后续请求中携带Token进行身份验证 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant LoginController as "LoginController" +participant UserService as "UserService" +participant TokenManager as "TokenManager" +Client->>LoginController : POST /api/login +LoginController->>UserService : 验证用户凭证 +UserService-->>LoginController : 返回用户信息 +LoginController->>TokenManager : 生成Token +TokenManager-->>LoginController : 返回JWT Token +LoginController-->>Client : 返回包含Token的响应 +``` + +**图示来源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L53-L58) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L51-L57) + +### Token生成与验证 + +Token的生成和验证由`TokenManager`类负责,基于JWT标准实现。Token包含用户身份信息和创建时间,并使用密钥进行签名。 + +```mermaid +flowchart TD +Start([开始]) --> GenerateClaims["生成声明(claims)"] +GenerateClaims --> AddUserInfo["添加用户信息(用户名、密码)"] +AddUserInfo --> AddCreateTime["添加创建时间"] +AddCreateTime --> SignToken["使用密钥签名Token"] +SignToken --> CompressToken["压缩Token"] +CompressToken --> ReturnToken["返回JWT Token"] +ReturnToken --> End([结束]) +``` + +**图示来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L51-L130) + +Token验证过程包括: +1. 解析Token获取声明信息 +2. 验证Token签名的有效性 +3. 检查Token是否过期 +4. 验证用户名和密码与系统存储的一致性 + +**本节来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L132-L196) + +## 自定义注解实现原理 + +DataVines通过自定义注解实现灵活的认证控制,主要包括`@AuthIgnore`和`@CheckTokenExist`两个注解。 + +### @AuthIgnore注解 + +`@AuthIgnore`注解用于标记不需要认证的方法,通常应用于登录、注册等公共接口。 + +```java +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthIgnore { +} +``` + +该注解的实现原理是在`AuthenticationInterceptor`中检查方法是否包含此注解,如果包含则跳过认证流程。 + +```mermaid +classDiagram +class AuthIgnore { ++@Target({ElementType.METHOD}) ++@Retention(RetentionPolicy.RUNTIME) +} +class AuthenticationInterceptor { ++preHandle(HttpServletRequest, HttpServletResponse, Object) +-checkAuthIgnore(Method) +-checkTokenExist(Method) +} +AuthenticationInterceptor --> AuthIgnore : "使用" +``` + +**图示来源** +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L66-L70) + +### @CheckTokenExist注解 + +`@CheckTokenExist`注解用于强制检查Token在数据库中的存在性,确保Token未被撤销。 + +```java +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckTokenExist { +} +``` + +当方法被此注解标记时,系统会查询数据库验证Token的有效性,而不仅仅是验证JWT签名。 + +**本节来源** +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L72-L87) + +## 全局认证拦截器 + +`AuthenticationInterceptor`是DataVines的核心认证拦截器,负责全局的请求认证处理。 + +### 拦截器配置 + +拦截器通过`WebMvcConfig`配置,对所有API路径进行拦截,但排除登录接口。 + +```java +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Bean + public AuthenticationInterceptor loginRequiredInterceptor() { + return new AuthenticationInterceptor(); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(loginRequiredInterceptor()) + .addPathPatterns(DataVinesConstants.BASE_API_PATH + "/**") + .excludePathPatterns(DataVinesConstants.BASE_API_PATH + "/login"); + } +} +``` + +### 认证流程 + +拦截器的认证流程如下: + +```mermaid +flowchart TD +Start([请求进入]) --> CheckHandler["检查Handler类型"] +CheckHandler --> IsHandlerMethod{"是HandlerMethod?"} +IsHandlerMethod --> |否| ReturnError["返回错误"] +IsHandlerMethod --> |是| GetMethod["获取方法对象"] +GetMethod --> CheckAuthIgnore["检查@AuthIgnore注解"] +CheckAuthIgnore --> ShouldIgnore{"需要忽略认证?"} +ShouldIgnore --> |是| AllowRequest["允许请求"] +ShouldIgnore --> |否| ExtractToken["提取Token"] +ExtractToken --> TokenExists{"Token存在?"} +TokenExists --> |否| ThrowTokenNullError["抛出Token为空异常"] +TokenExists --> |是| CheckTokenExistAnnotation["检查@CheckTokenExist注解"] +CheckTokenExistAnnotation --> NeedCheckExist{"需要检查存在性?"} +NeedCheckExist --> |是| VerifyTokenInDB["验证Token在数据库中存在"] +NeedCheckExist --> |否| ContinueProcess["继续处理"] +VerifyTokenInDB --> TokenValid{"Token有效?"} +TokenValid --> |否| ThrowInvalidTokenError["抛出无效Token异常"] +TokenValid --> |是| GetUsername["从Token获取用户名"] +GetUsername --> GetUser["根据用户名获取用户"] +GetUser --> UserExists{"用户存在?"} +UserExists --> |否| ThrowInvalidTokenError +UserExists --> |是| ValidateToken["验证Token签名和有效期"] +ValidateToken --> TokenValidated{"Token验证通过?"} +TokenValidated --> |否| ThrowInvalidTokenError +TokenValidated --> |是| SetUserContext["设置用户上下文"] +SetUserContext --> AllowRequest +AllowRequest --> End([请求通过]) +ThrowTokenNullError --> End +ThrowInvalidTokenError --> End +``` + +**本节来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java#L43-L48) + +## 权限控制模型 + +DataVines实现了基于用户、工作空间和租户的多层级权限控制模型。 + +### 用户-工作空间模型 + +系统采用用户-工作空间关联模型,一个用户可以属于多个工作空间,每个关联记录包含角色信息。 + +```mermaid +erDiagram +USER { +uuid id PK +string username +string password +boolean admin +timestamp create_time +timestamp update_time +} +WORKSPACE { +uuid id PK +string name +timestamp create_time +timestamp update_time +} +USER_WORKSPACE { +uuid id PK +uuid user_id FK +uuid workspace_id FK +uuid role_id FK +timestamp create_time +timestamp update_time +} +USER ||--o{ USER_WORKSPACE : "拥有" +WORKSPACE ||--o{ USER_WORKSPACE : "包含" +``` + +**图示来源** +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [UserWorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/UserWorkSpace.java) + +### 租户权限控制 + +租户(Tenant)作为工作空间内的资源隔离单位,实现更细粒度的权限控制。 + +```mermaid +graph TD +User[用户] --> |属于| WorkSpace[工作空间] +WorkSpace --> |包含| Tenant[租户] +Tenant --> |隔离| Resources[资源] +User --> |通过角色| Permissions[权限] +Permissions --> |控制| Tenant +``` + +**本节来源** +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) + +## AccessToken管理与有效期策略 + +### AccessToken实体 + +AccessToken存储在数据库中,包含Token字符串、关联的用户和工作空间、过期时间等信息。 + +```java +@Data +@TableName("dv_access_token") +public class AccessToken implements Serializable { + private Long id; + private Long workspaceId; + private Long userId; + private String token; + private LocalDateTime expireTime; + private Long createBy; + private LocalDateTime createTime; + private Long updateBy; + private LocalDateTime updateTime; +} +``` + +### Token有效期策略 + +系统采用双重有效期控制: +1. JWT Token自身的过期时间 +2. 数据库中记录的过期时间 + +Token创建时,系统会根据请求的过期时间生成JWT Token,并在数据库中记录相应的过期时间。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AccessTokenController as "AccessTokenController" +participant AccessTokenService as "AccessTokenService" +participant TokenManager as "TokenManager" +Client->>AccessTokenController : 创建Token请求 +AccessTokenController->>AccessTokenService : 调用create方法 +AccessTokenService->>TokenManager : 生成Token +TokenManager-->>AccessTokenService : 返回Token +AccessTokenService->>数据库 : 保存Token记录 +数据库-->>AccessTokenService : 保存成功 +AccessTokenService-->>AccessTokenController : 返回结果 +AccessTokenController-->>Client : 返回Token信息 +``` + +**本节来源** +- [AccessToken.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/AccessToken.java) +- [AccessTokenServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/AccessTokenServiceImpl.java) + +## 安全最佳实践 + +### 密码加密 + +系统在用户注册和登录时对密码进行加密处理,确保密码安全。 + +```mermaid +flowchart TD +Start([开始]) --> ReceivePassword["接收明文密码"] +ReceivePassword --> HashPassword["使用安全算法哈希"] +HashPassword --> StorePassword["存储哈希值"] +StorePassword --> VerifyPassword["验证时比较哈希值"] +VerifyPassword --> End([完成]) +``` + +**本节来源** +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java#L41-L42) + +### Token刷新机制 + +系统通过AOP实现Token自动刷新功能,延长用户会话有效期。 + +```java +@Aspect +@Component +@Order(Integer.MAX_VALUE) +public class RefreshTokenAop { + + @Pointcut("@within(RefreshToken)") + public void pointCut() { + } + + @Around(value = "pointCut()") + public Object doAroundReturningAdvice(ProceedingJoinPoint point) throws Throwable{ + Object[] args = point.getArgs(); + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + Object result = point.proceed(args); + return ResponseEntity.ok(new ResultMap(tokenManager).successAndRefreshToken(request).payload(result)); + } +} +``` + +**本节来源** +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) + +### 防止会话固定攻击 + +系统通过以下措施防止会话固定攻击: +1. 每次登录生成新的Token +2. 旧Token立即失效 +3. Token绑定用户凭证 +4. 支持Token撤销功能 + +## 扩展认证方式集成 + +### OAuth2集成指南 + +虽然当前系统主要使用JWT认证,但架构设计支持OAuth2等扩展认证方式的集成。 + +集成OAuth2需要实现以下步骤: +1. 添加OAuth2依赖 +2. 配置OAuth2客户端 +3. 实现OAuth2认证控制器 +4. 适配Token生成逻辑 +5. 更新拦截器以支持OAuth2 Token + +```mermaid +graph TD +OAuth2[OAuth2认证] --> |授权码| AuthorizationServer[授权服务器] +AuthorizationServer --> |授权码| Client[客户端] +Client --> |授权码| TokenEndpoint[Token端点] +TokenEndpoint --> |访问Token| Client +Client --> |访问Token| ResourceServer[资源服务器] +ResourceServer --> |验证Token| UserInfoEndpoint[用户信息端点] +``` + +**本节来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/API\351\233\206\346\210\220\344\270\216\346\225\260\346\215\256\346\265\201.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/API\351\233\206\346\210\220\344\270\216\346\225\260\346\215\256\346\265\201.md" new file mode 100644 index 00000000..b739e307 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/API\351\233\206\346\210\220\344\270\216\346\225\260\346\215\256\346\265\201.md" @@ -0,0 +1,286 @@ +# API集成与数据流 + + +**本文档中引用的文件** +- [index.ts](file://datavines-ui\src\http\index.ts) +- [rootReducer.ts](file://datavines-ui\src\store\rootReducer.ts) +- [store.ts](file://datavines-ui\src\store\index.ts) +- [User.ts](file://datavines-ui\src\type\User.ts) +- [Jobs.ts](file://datavines-ui\src\type\Jobs.ts) +- [dataSource.ts](file://datavines-ui\src\type\dataSource.ts) +- [constants.ts](file://datavines-ui\src\utils\constants.ts) +- [create.ts](file://datavines-ui\Editor\http\create.ts) +- [request.interceptor.ts](file://datavines-ui\Editor\http\request.interceptor.ts) +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts) +- [zh_CN.ts](file://datavines-ui\Editor\locale\zh_CN.ts) +- [en_US.ts](file://datavines-ui\Editor\locale\en_US.ts) +- [index.tsx](file://datavines-ui\src\locale\index.tsx) +- [index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx) +- [index.ts](file://datavines-ui\src\store\commonReducer\index.ts) + + +## 目录 +1. [简介](#简介) +2. [HTTP请求封装与拦截器实现](#http请求封装与拦截器实现) +3. [认证流程与令牌管理](#认证流程与令牌管理) +4. [Redux状态管理数据流](#redux状态管理数据流) +5. [类型定义与后端API对应关系](#类型定义与后端api对应关系) +6. [国际化错误消息与动态语言切换](#国际化错误消息与动态语言切换) +7. [API调试工具与网络问题排查](#api调试工具与网络问题排查) +8. [结论](#结论) + +## 简介 +本项目是一个大数据开源平台,提供数据质量监控和验证功能。系统由后端服务和前端UI组成,通过RESTful API进行通信。前端采用React + Redux技术栈,实现了完整的状态管理和API集成方案。本文档详细描述了前端与后端API的集成机制,包括HTTP请求封装、拦截器实现、错误处理、认证流程、Redux状态管理、国际化支持以及类型系统设计。 + +## HTTP请求封装与拦截器实现 + +前端通过自定义HTTP客户端封装了所有API请求,实现了统一的请求配置、拦截器和错误处理机制。HTTP客户端基于axios等库进行封装,提供了基础URL配置、请求和响应拦截器。 + +请求拦截器在每个请求发送前自动添加认证令牌和语言头信息,确保每个请求都携带必要的认证和上下文信息。响应拦截器负责处理服务器返回的响应,包括错误码处理、令牌刷新等。 + +**更新** 响应拦截器现已增强,支持国际化错误消息显示。系统内置了中英文错误消息映射表,能够根据当前语言设置动态显示对应的错误提示。 + +```mermaid +flowchart TD +A[发起API请求] --> B{请求拦截器} +B --> C[添加Authorization头] +C --> D[添加语言头] +D --> E[发送HTTP请求] +E --> F{响应拦截器} +F --> G{检查响应码} +G --> |认证失败| H[重定向到登录页] +G --> |包含新令牌| I[更新本地令牌] +I --> J[保存到Redux和SessionStorage] +G --> |HTTP错误| K{检查后端消息} +K --> |有结构化消息| L[使用后端消息] +K --> |无结构化消息| M[使用国际化错误消息] +M --> N[根据当前语言显示错误] +G --> |正常响应| O[返回数据] +``` + +**Diagram sources** +- [index.ts](file://datavines-ui\src\http\index.ts#L24-L50) +- [create.ts](file://datavines-ui\Editor\http\create.ts) +- [request.interceptor.ts](file://datavines-ui\Editor\http\request.interceptor.ts) +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts) + +**Section sources** +- [index.ts](file://datavines-ui\src\http\index.ts#L24-L50) +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts#L1-L106) + +## 认证流程与令牌管理 + +系统采用Bearer Token认证机制,用户登录后获取JWT令牌,并在后续请求中通过Authorization头传递。令牌管理机制确保了用户会话的安全性和连续性。 + +当用户成功登录后,令牌被存储在Redux状态树和浏览器的SessionStorage中,实现跨页面的状态共享。特别的是,系统实现了自动令牌刷新机制——当服务器在响应中返回新令牌时,前端会自动更新本地存储的令牌,延长用户会话有效期而无需重新登录。 + +认证失败处理机制完善,当检测到令牌过期或无效时(服务器返回特定错误码10010002、10010003、10010004),系统会在1秒后自动重定向到登录页面,提示用户重新认证。 + +```mermaid +sequenceDiagram +participant 前端 as 前端应用 +participant 服务器 as 后端服务器 +participant Redux as Redux Store +participant Storage as SessionStorage +前端->>服务器 : 登录请求(用户名/密码) +服务器-->>前端 : 返回令牌和用户信息 +前端->>Redux : 分发save_login action +前端->>Storage : 保存登录信息 +Redux-->>前端 : 更新userReducer状态 +前端->>服务器 : API请求(Authorization头) +服务器-->>前端 : 响应(可能包含新令牌) +前端->>前端 : 检查响应中的新令牌 +alt 存在新令牌 +前端->>Redux : 更新令牌 +前端->>Storage : 更新令牌 +end +alt 认证失败 +前端->>前端 : 延迟1秒后跳转登录页 +end +``` + +**Diagram sources** +- [index.ts](file://datavines-ui\src\http\index.ts#L9-L22) +- [index.ts](file://datavines-ui\src\http\index.ts#L39-L47) +- [constants.ts](file://datavines-ui\src\utils\constants.ts#L6) + +**Section sources** +- [index.ts](file://datavines-ui\src\http\index.ts#L9-L48) + +## Redux状态管理数据流 + +前端采用Redux作为状态管理解决方案,实现了集中式的状态存储和管理。状态树由多个reducer组成,分别管理用户、通用、工作空间和数据源等不同领域的状态。 + +Redux中间件配置包含了thunk和logger,支持异步action处理和开发调试。在开发环境中,还集成了redux-devtools-extension,便于开发者调试状态变化。 + +状态数据流遵循严格的单向数据流模式:组件发起action → Redux store处理action → reducer更新状态 → 组件重新渲染。通过useSelector和useDispatch等React-Redux钩子,组件可以订阅状态变化并分发action。 + +**更新** 通用reducer现在包含语言设置功能,支持动态语言切换。语言状态存储在Redux中,配合Cookie持久化,确保页面刷新后语言设置不丢失。 + +```mermaid +graph TD +A[UI组件] --> |dispatch| B[Action] +B --> C[Redux Store] +C --> D{Reducer} +D --> |userReducer| E[用户状态] +D --> |commonReducer| F[通用状态
包含语言设置] +D --> |workSpaceReducer| G[工作空间状态] +D --> |datasourceReducer| H[数据源状态] +E --> |subscribe| A +F --> |subscribe| A +G --> |subscribe| A +H --> |subscribe| A +I[中间件] --> C +I --> J[thunk] +I --> K[logger] +L[语言切换] --> F +L --> M[Cookie持久化] +``` + +**Diagram sources** +- [store.ts](file://datavines-ui\src\store\index.ts#L12-L15) +- [rootReducer.ts](file://datavines-ui\src\store\rootReducer.ts#L6-L11) +- [store.ts](file://datavines-ui\src\store\index.ts#L20-L23) +- [index.ts](file://datavines-ui\src\store\commonReducer\index.ts#L41-L53) + +**Section sources** +- [store.ts](file://datavines-ui\src\store\index.ts#L1-L26) +- [rootReducer.ts](file://datavines-ui\src\store\rootReducer.ts#L1-L26) +- [index.ts](file://datavines-ui\src\store\commonReducer\index.ts#L1-L73) + +## 类型定义与后端API对应关系 + +项目采用TypeScript进行类型定义,确保前端与后端API的数据结构保持一致。类型系统定义了各种业务实体的接口,包括用户、作业、数据源等。 + +类型定义文件位于src/type目录下,为前端组件提供了类型安全的开发体验。通过精确的接口定义,开发人员可以清楚地了解API返回的数据结构,减少运行时错误。 + +类型系统与后端Java实体类对应,确保了前后端数据契约的一致性。例如,用户信息接口TUserItem与后端User实体对应,作业数据接口TJobsTableData与后端JobExecutionInfo对应。 + +```mermaid +classDiagram +class TUserItem { ++id? : any ++email? : string ++username? : string ++updateTime? : string ++updateBy? : string +} +class TJobsTableItem { ++id : string | number ++type? : string +} +class TJobsTableData { ++list : TJobsTableItem[] ++total : number +} +class IDataSourceListItem { ++id : number ++name : string ++param : string ++type : string ++updater : string ++updateTime : string +} +class IDataSourceList { ++total : number ++list : IDataSourceListItem[] +} +TJobsTableData --> TJobsTableItem : "包含" +IDataSourceList --> IDataSourceListItem : "包含" +``` + +**Diagram sources** +- [User.ts](file://datavines-ui\src\type\User.ts#L1-L8) +- [Jobs.ts](file://datavines-ui\src\type\Jobs.ts#L1-L10) +- [dataSource.ts](file://datavines-ui\src\type\dataSource.ts#L36-L50) + +**Section sources** +- [User.ts](file://datavines-ui\src\type\User.ts#L1-L8) +- [Jobs.ts](file://datavines-ui\src\type\Jobs.ts#L1-L10) +- [dataSource.ts](file://datavines-ui\src\type\dataSource.ts#L1-L50) + +## 国际化错误消息与动态语言切换 + +**新增** 系统现已支持国际化错误消息显示和动态语言切换功能。这一增强功能通过HTTP响应拦截器实现,为用户提供多语言的错误提示体验。 + +### 国际化错误消息支持 + +响应拦截器内置了中英文错误消息映射表,覆盖了常见的网络错误、HTTP状态码错误和超时错误场景: + +- **网络连接失败**:网络连接失败,无法连接到服务器 / Network connection failed, unable to connect to server +- **请求超时**:请求超时,请检查网络后重试 / Request timeout, please check your network +- **HTTP状态码错误**:400、401、403、404、500、502、503、504等标准HTTP错误码 +- **未知错误**:服务器错误 / Server error + +### 动态语言切换机制 + +系统通过以下组件和状态管理实现动态语言切换: + +1. **语言状态管理**:commonReducer维护当前语言设置,默认为'en_US' +2. **语言切换组件**:SwitchLanguage组件提供简体中文/English切换功能 +3. **国际化包装器**:IntlWrap组件根据Redux状态提供对应语言的消息 +4. **错误消息国际化**:响应拦截器使用当前语言设置显示对应错误消息 + +```mermaid +flowchart TD +A[用户切换语言] --> B[SwitchLanguage组件] +B --> C[commonReducer.setLocale] +C --> D[Redux状态更新] +D --> E[Cookie持久化] +E --> F[IntlWrap组件] +F --> G[IntlProvider语言设置] +G --> H[响应拦截器] +H --> I[setHttpErrorLocale] +I --> J[根据语言显示错误消息] +K[错误发生] --> L[响应拦截器] +L --> M{检查后端消息} +M --> |有| N[使用后端消息] +M --> |无| O[使用国际化消息] +O --> P[getErrorMessage] +P --> Q[errorMessages[currentLocale]] +Q --> R[显示对应语言错误] +``` + +**Diagram sources** +- [index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx#L1-L38) +- [index.ts](file://datavines-ui\src\store\commonReducer\index.ts#L41-L53) +- [index.tsx](file://datavines-ui\src\locale\index.tsx#L32-L55) +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts#L4-L10) +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts#L42-L45) + +**Section sources** +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts#L1-L106) +- [zh_CN.ts](file://datavines-ui\Editor\locale\zh_CN.ts#L1-L85) +- [en_US.ts](file://datavines-ui\Editor\locale\en_US.ts#L1-L85) +- [index.tsx](file://datavines-ui\src\locale\index.tsx#L1-L56) +- [index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx#L1-L38) +- [index.ts](file://datavines-ui\src\store\commonReducer\index.ts#L1-L73) + +## API调试工具与网络问题排查 + +系统提供了完善的API调试和网络问题排查机制。开发人员可以利用浏览器开发者工具的Network面板监控所有API请求和响应,检查请求头、响应码和数据负载。 + +Redux DevTools是另一个重要的调试工具,可以追踪所有action的分发和状态变化,帮助理解应用的状态流转。结合redux-logger中间件,可以在控制台查看详细的状态变化日志。 + +**更新** 新增国际化错误消息调试功能。开发人员可以通过检查响应拦截器中的错误消息映射表来验证多语言支持是否正常工作。 + +对于常见的网络问题,系统提供了相应的排查指南: +- **认证失败**:检查令牌是否过期,确认登录状态 +- **跨域问题**:确认后端CORS配置是否正确 +- **请求超时**:检查网络连接,确认后端服务是否正常运行 +- **数据格式错误**:检查API响应结构是否符合类型定义 +- **国际化错误消息问题**:检查当前语言设置和错误消息映射表 + +错误处理机制捕获并处理各种网络异常,提供用户友好的错误提示。对于特定的业务错误码,系统会执行相应的处理逻辑,如重定向到登录页。新增的国际化错误消息功能确保了用户能够看到对应语言的错误提示。 + +**Section sources** +- [index.ts](file://datavines-ui\src\http\index.ts#L39-L43) +- [store.ts](file://datavines-ui\src\store\index.ts#L7) +- [response.interceptor.ts](file://datavines-ui\Editor\http\response.interceptor.ts#L66-L105) + +## 结论 +本项目实现了完整的前端与后端API集成方案,通过HTTP拦截器、Redux状态管理和TypeScript类型系统,构建了健壮、可维护的应用架构。认证机制安全可靠,支持令牌自动刷新;状态管理清晰有序,遵循单向数据流原则;类型系统确保了前后端数据契约的一致性。 + +**更新亮点** 新增的国际化错误消息支持和动态语言切换功能进一步提升了用户体验。通过响应拦截器的增强实现,系统现在能够根据用户的语言偏好显示对应的错误提示,支持中英文双语环境下的错误消息显示。配合Redux状态管理和Cookie持久化机制,实现了无缝的语言切换体验。 + +这些设计模式为大型前端应用的开发提供了良好的实践参考,特别是在国际化支持和错误处理方面的最佳实践值得借鉴。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/UI\347\273\204\344\273\266\347\263\273\347\273\237.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/UI\347\273\204\344\273\266\347\263\273\347\273\237.md" new file mode 100644 index 00000000..222aaebb --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/UI\347\273\204\344\273\266\347\263\273\347\273\237.md" @@ -0,0 +1,291 @@ +# UI组件系统 + + +**本文档引用的文件** +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [Title\index.tsx](file://datavines-ui\src\component\Title\index.tsx) +- [GoBack\index.tsx](file://datavines-ui\src\component\GoBack\index.tsx) +- [SwitchLanguage\index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx) +- [ContentLayout\index.tsx](file://datavines-ui\src\component\ContentLayout\index.tsx) +- [global.less](file://datavines-ui\src\global.less) +- [package.json](file://datavines-ui\package.json) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细描述了Datavines项目的UI组件系统,重点介绍导航菜单、页头、搜索表单、标题栏等核心组件的设计与实现。文档解释了组件的props接口、事件处理和样式定制方法,分析了高阶组件如KeepAlive的实现原理和使用场景。同时提供了组件复用的最佳实践和自定义组件开发指南,包含组件测试策略和性能优化建议。 + +## 项目结构 +Datavines的UI组件系统位于`datavines-ui`目录下,采用模块化设计,将不同功能的组件分类存放。核心组件主要分布在`src/component`目录中,包括Header(页头)、SearchForm(搜索表单)、Title(标题栏)、KeepAlive(页面缓存)等。 + +```mermaid +graph TD +A[datavines-ui] --> B[src/component] +B --> C[Header] +B --> D[SearchForm] +B --> E[Title] +B --> F[KeepAlive] +B --> G[GoBack] +B --> H[SwitchLanguage] +B --> I[ContentLayout] +C --> J[Logo] +C --> K[Settings] +C --> L[WorkSpaceSwitch] +``` + +**图示来源** +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [Title\index.tsx](file://datavines-ui\src\component\Title\index.tsx) + +**章节来源** +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [Title\index.tsx](file://datavines-ui\src\component\Title\index.tsx) + +## 核心组件 +本系统的核心UI组件包括页头(Header)、搜索表单(SearchForm)、标题栏(Title)和页面缓存(KeepAlive)等。这些组件共同构成了Datavines应用的用户界面基础,提供了统一的视觉风格和交互体验。 + +**章节来源** +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [Title\index.tsx](file://datavines-ui\src\component\Title\index.tsx) +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) + +## 架构概述 +Datavines UI组件系统采用React函数式组件和Hooks的现代开发模式,结合Ant Design组件库构建用户界面。系统通过模块化设计将不同功能的组件分离,同时利用Context API和Redux进行状态管理。 + +```mermaid +graph TD +A[React] --> B[函数式组件] +A --> C[Hooks] +A --> D[Context API] +B --> E[Header] +B --> F[SearchForm] +B --> G[Title] +B --> H[KeepAlive] +C --> I[useEffect] +C --> J[useState] +C --> K[useMemo] +C --> L[useCallback] +D --> M[KeepAliveContext] +N[Ant Design] --> O[UI组件] +P[Redux] --> Q[状态管理] +E --> R[Logo] +E --> S[Settings] +E --> T[WorkSpaceSwitch] +``` + +**图示来源** +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [package.json](file://datavines-ui\package.json) + +## 详细组件分析 +### 页头组件分析 +页头组件(Header)是应用的顶部导航区域,包含Logo、工作空间切换和设置功能。组件采用函数式编程模式,通过组合多个子组件实现完整功能。 + +#### 组件结构 +```mermaid +classDiagram +class Header { ++render() JSX.Element +} +class Logo { ++render() JSX.Element +} +class WorkSpaceSwitch { ++render() JSX.Element +} +class Settings { ++render() JSX.Element +} +Header --> Logo : 包含 +Header --> WorkSpaceSwitch : 包含 +Header --> Settings : 包含 +``` + +**图示来源** +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [Header\Logo\index.tsx](file://datavines-ui\src\component\Header\Logo\index.tsx) +- [Header\Settings\index.tsx](file://datavines-ui\src\component\Header\Settings\index.tsx) +- [Header\WorkSpaceSwitch\index.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\index.tsx) + +**章节来源** +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [Header\Logo\index.tsx](file://datavines-ui\src\component\Header\Logo\index.tsx) +- [Header\Settings\index.tsx](file://datavines-ui\src\component\Header\Settings\index.tsx) +- [Header\WorkSpaceSwitch\index.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\index.tsx) + +### 搜索表单组件分析 +搜索表单(SearchForm)组件提供统一的搜索功能,支持自定义搜索回调和表单实例。 + +#### 属性接口 +| 属性名 | 类型 | 必需 | 默认值 | 描述 | +|-------|------|------|--------|------| +| onSearch | (val: string) => void | 是 | 无 | 搜索回调函数 | +| form | FormInstance | 否 | 无 | 表单实例 | +| placeholder | string | 否 | '搜索...' | 占位符文本 | + +#### 组件实现流程 +```mermaid +flowchart TD +Start([组件初始化]) --> CheckForm["检查是否传入form实例"] +CheckForm --> |是| UseProvidedForm["使用传入的form实例"] +CheckForm --> |否| CreateNewForm["创建新的form实例"] +UseProvidedForm --> RenderForm["渲染表单"] +CreateNewForm --> RenderForm +RenderForm --> HandleSearch["处理搜索事件"] +HandleSearch --> GetValues["获取表单值"] +GetValues --> CallCallback["调用onSearch回调"] +CallCallback --> End([完成]) +``` + +**图示来源** +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) + +**章节来源** +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) + +### 标题栏组件分析 +标题栏(Title)组件用于显示页面标题,可选择是否显示返回按钮。 + +#### 属性接口 +| 属性名 | 类型 | 必需 | 默认值 | 描述 | +|-------|------|------|--------|------| +| isBack | boolean | 否 | false | 是否显示返回按钮 | +| children | React.ReactNode | 是 | 无 | 标题内容 | + +#### 组件渲染逻辑 +```mermaid +flowchart TD +Start([组件渲染]) --> CheckIsBack["检查isBack属性"] +CheckIsBack --> |true| RenderWithBack["渲染带返回按钮的标题"] +CheckIsBack --> |false| RenderWithoutBack["渲染不带返回按钮的标题"] +RenderWithBack --> AddBackButton["添加GoBack组件"] +RenderWithoutBack --> OnlyTitle["仅显示标题内容"] +AddBackButton --> End([完成]) +OnlyTitle --> End +``` + +**图示来源** +- [Title\index.tsx](file://datavines-ui\src\component\Title\index.tsx) +- [GoBack\index.tsx](file://datavines-ui\src\component\GoBack\index.tsx) + +**章节来源** +- [Title\index.tsx](file://datavines-ui\src\component\Title\index.tsx) +- [GoBack\index.tsx](file://datavines-ui\src\component\GoBack\index.tsx) + +### KeepAlive组件分析 +KeepAlive组件是高阶组件,用于实现页面状态缓存,避免组件重复渲染。 + +#### 实现原理 +```mermaid +classDiagram +class KeepAlive { ++components : RefObject> ++containerRef : RefObject ++destroy(params : string, render? : boolean) : void ++render() : JSX.Element +} +class Component { ++targetElement : HTMLDivElement ++activatedRef : RefObject ++render() : JSX.Element +} +class KeepAliveContext { ++destroy : (params : string, render? : boolean) => void ++isActive : boolean +} +KeepAlive --> Component : 渲染 +KeepAlive --> KeepAliveContext : 提供 +Component --> ReactDOM.createPortal : 使用 +``` + +**图示来源** +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) + +**章节来源** +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) + +## 依赖分析 +UI组件系统依赖于多个第三方库和内部模块,形成了完整的依赖关系网络。 + +```mermaid +graph TD +A[datavines-ui] --> B[react] +A --> C[react-dom] +A --> D[antd] +A --> E[ahooks] +A --> F[ramda] +A --> G[react-intl] +A --> H[react-router-dom] +B --> I[React核心] +C --> J[DOM渲染] +D --> K[Ant Design组件] +E --> L[React Hooks工具] +F --> M[函数式编程工具] +G --> N[国际化支持] +H --> O[路由管理] +A --> P[自定义组件] +P --> Q[Header] +P --> R[SearchForm] +P --> S[Title] +P --> T[KeepAlive] +``` + +**图示来源** +- [package.json](file://datavines-ui\package.json) +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [Title\index.tsx](file://datavines-ui\src\component\Title\index.tsx) + +**章节来源** +- [package.json](file://datavines-ui\package.json) +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [Title\index.tsx](file://datavines-ui\src\component\Title\index.tsx) + +## 性能考虑 +UI组件系统在设计时充分考虑了性能优化,采用了多种技术手段提升应用性能。 + +1. **组件记忆化**: 所有组件都使用`React.memo`进行记忆化,避免不必要的重新渲染。 +2. **状态管理**: 使用`useRef`存储组件状态,避免状态变化导致的重新渲染。 +3. **虚拟DOM**: 利用React的虚拟DOM机制,最小化DOM操作。 +4. **懒加载**: 通过`createPortal`实现组件的按需渲染。 +5. **缓存机制**: KeepAlive组件实现了页面状态缓存,避免重复的数据获取和渲染。 + +**章节来源** +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) +- [Header\index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [SearchForm\index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [Title\index.tsx](file://datavines-ui\src\component\Title\index.tsx) + +## 故障排除指南 +### 常见问题及解决方案 +1. **组件不渲染**: 检查组件是否正确导入和使用,确保props传递正确。 +2. **样式不生效**: 检查CSS类名是否正确,确认样式文件已正确引入。 +3. **状态不更新**: 确认使用了正确的状态管理方法,检查依赖数组是否正确。 +4. **国际化失效**: 检查语言包是否正确配置,确认`useIntl`钩子使用正确。 + +**章节来源** +- [global.less](file://datavines-ui\src\global.less) +- [SwitchLanguage\index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx) +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) + +## 结论 +Datavines的UI组件系统采用现代化的React开发模式,通过模块化设计和高阶组件实现了高效、可复用的用户界面。系统提供了完整的组件库,包括页头、搜索表单、标题栏等核心组件,并通过KeepAlive组件实现了页面状态缓存。组件系统具有良好的性能表现和可维护性,为Datavines应用提供了统一的用户体验。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/\345\267\245\345\205\267\347\261\273\347\273\204\344\273\266.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/\345\267\245\345\205\267\347\261\273\347\273\204\344\273\266.md" new file mode 100644 index 00000000..02b41935 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/\345\267\245\345\205\267\347\261\273\347\273\204\344\273\266.md" @@ -0,0 +1,183 @@ +# 工具类组件 + + +**本文档中引用的文件** +- [GoBack/index.tsx](file://datavines-ui\src\component\GoBack\index.tsx) +- [SwitchLanguage/index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx) +- [index.tsx](file://datavines-ui\src\component\index.tsx) +- [commonReducer/index.ts](file://datavines-ui\src\store\commonReducer\index.ts) +- [locale/index.tsx](file://datavines-ui\src\locale\index.tsx) +- [constants.ts](file://datavines-ui\src\utils\constants.ts) +- [shareData/index.ts](file://datavines-ui\src\utils\shareData\index.ts) +- [zh_CN.ts](file://datavines-ui\src\locale\zh_CN.ts) +- [en_US.ts](file://datavines-ui\src\locale\en_US.ts) +- [App/index.tsx](file://datavines-ui\src\App\index.tsx) + + +## 目录 +1. [简介](#简介) +2. [核心组件分析](#核心组件分析) +3. [GoBack返回按钮组件](#goback返回按钮组件) +4. [SwitchLanguage语言切换组件](#switchlanguage语言切换组件) +5. [组件入口文件index.tsx](#组件入口文件indextsx) +6. [国际化集成机制](#国际化集成机制) +7. [全局状态管理协作模式](#全局状态管理协作模式) +8. [应用场景案例](#应用场景案例) +9. [开发效率与用户体验一致性提升](#开发效率与用户体验一致性提升) + +## 简介 +本文档系统化地文档化了Datavines项目中的工具类组件,重点关注GoBack返回按钮、SwitchLanguage语言切换组件以及组件入口文件index.tsx的导出规范。详细说明了这些轻量级组件如何提升开发效率和用户体验一致性,并提供了在表单页面、详情页和国际化场景下的具体应用案例。 + +## 核心组件分析 +本节分析Datavines项目中的核心工具类组件,包括GoBack返回按钮、SwitchLanguage语言切换组件等,这些组件通过封装常用功能,提高了代码复用性和开发效率。 + +**Section sources** +- [GoBack/index.tsx](file://datavines-ui\src\component\GoBack\index.tsx) +- [SwitchLanguage/index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx) + +## GoBack返回按钮组件 +GoBack组件是一个轻量级的返回按钮工具,用于处理路由历史的返回操作。该组件基于React和React Router实现,通过调用浏览器的历史记录API来实现页面返回功能。 + +组件接受可选的样式和子元素作为props,如果未提供子元素,则默认显示一个Ant Design的ArrowLeftOutlined图标。点击按钮时,会触发history.goBack()方法,返回到上一个路由。 + +该组件使用React.memo进行性能优化,避免不必要的重新渲染。其主要功能是提供一致的返回用户体验,无论是在表单页面还是详情页中都能保持统一的交互模式。 + +```mermaid +flowchart TD +A[用户点击GoBack按钮] --> B{是否有自定义子元素?} +B --> |是| C[显示自定义内容] +B --> |否| D[显示默认箭头图标] +C --> E[触发history.goBack()] +D --> E +E --> F[返回上一个路由] +``` + +**Diagram sources** +- [GoBack/index.tsx](file://datavines-ui\src\component\GoBack\index.tsx) + +**Section sources** +- [GoBack/index.tsx](file://datavines-ui\src\component\GoBack\index.tsx) + +## SwitchLanguage语言切换组件 +SwitchLanguage组件实现了系统的国际化语言切换功能。该组件基于React Intl和Redux状态管理,允许用户在不同语言之间切换。 + +组件使用Popover包裹语言切换选项,点击时会切换当前语言环境。语言映射定义在组件内部,支持中文(zh_CN)和英文(en_US)两种语言。切换语言时,组件会更新Redux中的locale状态,并将选择的语言存储到localStorage中,确保页面刷新后仍能保持用户选择的语言偏好。 + +该组件通过useSelector获取当前语言状态,通过useCommonActions获取状态更新函数,实现了与全局状态管理的无缝集成。语言切换后,所有使用React Intl格式化的文本都会自动更新为对应语言的翻译。 + +```mermaid +flowchart TD +A[用户点击语言切换] --> B[获取当前语言状态] +B --> C{当前语言是zh_CN?} +C --> |是| D[切换到en_US] +C --> |否| E[切换到zh_CN] +D --> F[更新Redux状态] +E --> F +F --> G[存储到localStorage] +G --> H[触发界面重新渲染] +H --> I[所有文本更新为新语言] +``` + +**Diagram sources** +- [SwitchLanguage/index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx) +- [commonReducer/index.ts](file://datavines-ui\src\store\commonReducer\index.ts) +- [shareData/index.ts](file://datavines-ui\src\utils\shareData\index.ts) + +**Section sources** +- [SwitchLanguage/index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx) + +## 组件入口文件index.tsx +组件入口文件index.tsx位于src/component目录下,负责统一导出所有工具类组件。该文件采用模块化设计,通过命名导出方式暴露GoBack、SwitchLanguage、Title、SearchForm等核心组件。 + +这种集中式导出模式提供了清晰的组件API入口,使得其他模块可以方便地导入所需组件。通过在单个文件中管理所有组件的导出,降低了组件引用的复杂性,提高了代码的可维护性。 + +该文件的结构简洁明了,仅包含导入和导出语句,不包含任何业务逻辑,符合单一职责原则。这种设计模式使得组件的引入和使用变得非常直观和一致。 + +**Section sources** +- [index.tsx](file://datavines-ui\src\component\index.tsx) + +## 国际化集成机制 +Datavines项目的国际化机制基于React Intl实现,通过IntlProvider组件提供多语言支持。系统支持中英文两种语言,并通过locale文件存储翻译文本。 + +在应用启动时,App组件会从localStorage或浏览器语言设置中读取用户的语言偏好,并初始化相应的语言环境。如果localStorage中没有存储语言设置,则根据浏览器语言自动选择中文或英文。 + +翻译文本存储在zh_CN.ts和en_US.ts两个文件中,包含所有用户界面的文本内容。这些翻译文件通过locale/index.tsx进行整合,并与React Intl的IntlProvider组件集成,确保所有文本都能根据当前语言环境正确显示。 + +```mermaid +flowchart TD +A[应用启动] --> B[读取语言偏好] +B --> C{localStorage有设置?} +C --> |是| D[使用localStorage中的语言] +C --> |否| E[根据浏览器语言自动选择] +D --> F[初始化IntlProvider] +E --> F +F --> G[加载对应语言的翻译文件] +G --> H[渲染界面文本] +``` + +**Diagram sources** +- [App/index.tsx](file://datavines-ui\src\App\index.tsx) +- [locale/index.tsx](file://datavines-ui\src\locale\index.tsx) +- [constants.ts](file://datavines-ui\src\utils\constants.ts) + +**Section sources** +- [App/index.tsx](file://datavines-ui\src\App\index.tsx) +- [locale/index.tsx](file://datavines-ui\src\locale\index.tsx) + +## 全局状态管理协作模式 +工具类组件与Redux全局状态管理紧密协作,通过useSelector和useDispatch(通过useCommonActions封装)实现状态的读取和更新。 + +SwitchLanguage组件通过useSelector订阅commonReducer中的locale状态,当语言切换时,通过useCommonActions派发setLocale action来更新全局状态。GoBack组件虽然不直接依赖Redux状态,但其功能依赖于React Router的history对象,而路由状态也是应用全局状态的一部分。 + +commonReducer中定义了locale、prefixCls等全局UI状态,这些状态被多个组件共享和使用。通过Redux的单一数据源原则,确保了应用状态的一致性和可预测性。 + +```mermaid +classDiagram +class SwitchLanguage { ++useSelector() ++useCommonActions() ++swichFn() +} +class commonReducer { ++locale : 'zh_CN'|'en_US' ++prefixCls : 'dark'|undefined ++isDetailPage : boolean +} +class useCommonActions { ++setLocale(locale) ++setPrefixCls(prefixCls) ++setIsDetailPage(isDetailPage) +} +SwitchLanguage --> commonReducer : "订阅" +SwitchLanguage --> useCommonActions : "使用" +useCommonActions --> commonReducer : "更新" +``` + +**Diagram sources** +- [SwitchLanguage/index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx) +- [commonReducer/index.ts](file://datavines-ui\src\store\commonReducer\index.ts) + +**Section sources** +- [commonReducer/index.ts](file://datavines-ui\src\store\commonReducer\index.ts) + +## 应用场景案例 +### 表单页面应用 +在表单页面中,GoBack组件通常位于页面顶部,允许用户在填写表单时返回上一页。SwitchLanguage组件则提供语言切换功能,方便不同语言用户使用系统。 + +### 详情页应用 +在详情页中,GoBack组件帮助用户从详情视图返回列表页面。通过isDetailPage状态的管理,系统可以智能地显示或隐藏某些UI元素,提供更合适的用户体验。 + +### 国际化场景 +系统通过SwitchLanguage组件和React Intl的结合,实现了完整的国际化支持。用户可以在界面中随时切换语言,所有文本内容都会相应更新。语言偏好会持久化存储在localStorage中,确保用户体验的一致性。 + +## 开发效率与用户体验一致性提升 +这些工具类组件通过封装常用功能,显著提升了开发效率。开发者无需重复实现返回按钮或语言切换逻辑,可以直接导入和使用这些经过验证的组件。 + +同时,这些组件确保了用户体验的一致性。无论在应用的哪个部分,返回按钮和语言切换的交互方式都保持统一,降低了用户的学习成本,提高了系统的可用性。 + +通过集中管理和维护这些通用组件,团队可以更容易地进行UI更新和优化,确保整个应用的视觉和交互一致性。 + +**Section sources** +- [GoBack/index.tsx](file://datavines-ui\src\component\GoBack\index.tsx) +- [SwitchLanguage/index.tsx](file://datavines-ui\src\component\SwitchLanguage\index.tsx) +- [index.tsx](file://datavines-ui\src\component\index.tsx) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/\345\270\203\345\261\200\347\273\204\344\273\266.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/\345\270\203\345\261\200\347\273\204\344\273\266.md" new file mode 100644 index 00000000..ef2a940d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/\345\270\203\345\261\200\347\273\204\344\273\266.md" @@ -0,0 +1,228 @@ +# 布局组件 + + +**本文档引用的文件** +- [ContentLayout/index.tsx](file://datavines-ui/src/component/ContentLayout/index.tsx) +- [Menu/Layout/index.tsx](file://datavines-ui/src/component/Menu/Layout/index.tsx) +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx) +- [Header/index.tsx](file://datavines-ui/src/component/Header/index.tsx) +- [mainRouter.tsx](file://datavines-ui/src/router/mainRouter.tsx) +- [useRoute.tsx](file://datavines-ui/src/router/useRoute.tsx) +- [Main/index.tsx](file://datavines-ui/src/view/Main/index.tsx) +- [rootReducer.ts](file://datavines-ui/src/store/rootReducer.ts) +- [constants.ts](file://datavines-ui/src/utils/constants.ts) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档深入解析 DataVines 数据质量平台前端系统的布局组件架构设计与实现细节。重点阐述 `MenuAside` 侧边栏菜单的路由映射逻辑、动态权限控制和展开/收起交互;分析 `Layout` 布局容器的响应式设计和嵌套结构;说明 `ContentLayout` 内容区域的自适应填充机制。文档化组件的配置参数、插槽使用和主题定制能力,并提供多级菜单渲染、权限路由集成和移动端适配的最佳实践。 + +## 项目结构 +布局组件主要位于 `datavines-ui` 项目的 `src/component` 目录下,采用模块化设计,各组件职责清晰,通过 React 和 Ant Design 实现现代化的用户界面。 + +```mermaid +graph TD +subgraph "布局组件" +A[MenuLayout] --> B[MenuAside] +A --> C[Header] +D[ContentLayout] +end +subgraph "状态与路由" +E[Redux Store] +F[React Router] +end +A --> E +B --> E +C --> E +A --> F +B --> F +D --> F +``` + +**图示来源** +- [Menu/Layout/index.tsx](file://datavines-ui/src/component/Menu/Layout/index.tsx) +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx) +- [Header/index.tsx](file://datavines-ui/src/component/Header/index.tsx) +- [ContentLayout/index.tsx](file://datavines-ui/src/component/ContentLayout/index.tsx) +- [store/index.ts](file://datavines-ui/src/store/index.ts) +- [router/useRoute.tsx](file://datavines-ui/src/router/useRoute.tsx) + +**本节来源** +- [datavines-ui/src/component/Menu/Layout/index.tsx](file://datavines-ui/src/component/Menu/Layout/index.tsx) +- [datavines-ui/src/component/Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx) +- [datavines-ui/src/component/Header/index.tsx](file://datavines-ui/src/component/Header/index.tsx) + +## 核心组件 +核心布局组件包括 `MenuLayout`、`MenuAside`、`Header` 和 `ContentLayout`。`MenuLayout` 是主布局容器,负责整合侧边栏、头部和内容区域。`MenuAside` 实现了侧边栏菜单的渲染和交互逻辑,支持多级菜单和动态路由映射。`Header` 组件包含工作区切换、语言设置和用户信息。`ContentLayout` 提供了内容区域的样式封装,确保内容自适应填充。 + +**本节来源** +- [Menu/Layout/index.tsx](file://datavines-ui/src/component/Menu/Layout/index.tsx#L1-L57) +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx#L1-L237) +- [Header/index.tsx](file://datavines-ui/src/component/Header/index.tsx#L1-L16) +- [ContentLayout/index.tsx](file://datavines-ui/src/component/ContentLayout/index.tsx#L1-L23) + +## 架构概述 +系统采用 React + Redux + React Router 的经典架构。`Main` 组件作为应用主入口,通过 `useRoute` 钩子获取路由配置,并将路由信息转换为 `MenuAside` 所需的菜单项。`MenuLayout` 作为布局骨架,接收菜单数据并渲染侧边栏和内容区域。状态管理通过 Redux 实现,`workSpaceReducer` 和 `commonReducer` 分别管理工作区和通用状态,为布局组件提供数据支持。 + +```mermaid +sequenceDiagram +participant Main as "Main组件" +participant UseRoute as "useRoute钩子" +participant Router as "路由配置" +participant MenuLayout as "MenuLayout" +participant MenuAside as "MenuAside" +participant Store as "Redux Store" +Main->>UseRoute : 调用useRoute() +UseRoute->>Router : 读取mainRouter.tsx +Router-->>UseRoute : 返回路由数组 +UseRoute-->>Main : 返回routes +Main->>Store : useSelector获取状态 +Store-->>Main : 返回workspaceId, locale等 +Main->>MenuLayout : 传递menus和visible +MenuLayout->>MenuAside : 传递menus +MenuAside->>Store : useSelector获取用户信息 +Store-->>MenuAside : 返回loginInfo, spaceList +MenuAside->>MenuAside : 渲染菜单和用户Popover +``` + +**图示来源** +- [view/Main/index.tsx](file://datavines-ui/src/view/Main/index.tsx#L1-L62) +- [router/useRoute.tsx](file://datavines-ui/src/router/useRoute.tsx#L1-L69) +- [router/mainRouter.tsx](file://datavines-ui/src/router/mainRouter.tsx#L1-L62) +- [store/rootReducer.ts](file://datavines-ui/src/store/rootReducer.ts#L1-L26) + +## 详细组件分析 + +### MenuAside 侧边栏菜单分析 +`MenuAside` 组件负责渲染侧边栏菜单,其核心功能包括路由映射、菜单激活状态管理和用户交互。 + +#### 路由映射与激活逻辑 +组件通过 `setActiveKeyRedirect` 函数实现路由到菜单项的映射。该函数在组件挂载时通过 `useWatch` 监听 `menus` 变化,根据当前 URL 匹配对应的菜单项,并设置 `activeKeys` 以高亮显示当前页面对应的菜单。对于包含动态参数(如 `:id`)的路由,函数会进行特殊处理,确保正确匹配。 + +```mermaid +flowchart TD +Start([组件挂载]) --> WatchMenus["useWatch监听menus变化"] +WatchMenus --> GetURL["获取当前window.location.href"] +GetURL --> FindMatch["遍历menus查找匹配项"] +FindMatch --> HasParam{"路径包含:id?"} +HasParam --> |是| SplitPath["按:id分割路径"] +HasParam --> |否| DirectMatch["直接检查URL是否包含path"] +SplitPath --> CheckContains["检查URL是否包含分割后的路径"] +DirectMatch --> MatchResult +CheckContains --> MatchResult +MatchResult --> Found{"找到匹配项?"} +Found --> |是| SetActive["设置activeKeys为匹配项key"] +Found --> |否| UseFirst["使用menus[0]作为默认"] +SetActive --> Redirect{"需要重定向?"} +UseFirst --> Redirect +Redirect --> |是| PushHistory["history.push(currItem.path)"] +Redirect --> |否| End([完成]) +PushHistory --> End +``` + +**图示来源** +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx#L46-L67) +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx#L68) + +**本节来源** +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx#L1-L237) + +#### 动态权限控制与菜单过滤 +组件通过 `menuHide` 属性实现菜单项的动态显示控制。在渲染前,`$munus` 数组通过 `filter` 方法过滤掉 `menuHide` 为 `true` 的菜单项,从而实现基于权限或状态的菜单隐藏。此机制在 `mainRouter.tsx` 中通过设置 `'dv-home-detail'` 路由的 `menuHide: true` 来隐藏详情页路由,确保其不显示在侧边栏中。 + +**本节来源** +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx#L171) +- [router/mainRouter.tsx](file://datavines-ui/src/router/mainRouter.tsx#L35) + +#### 展开/收起交互 +`MenuAside` 组件本身不直接处理展开/收起逻辑,而是由其父组件 `MenuLayout` 管理。`MenuLayout` 使用 `useState` 管理 `collapsed` 状态,并通过 `Sider` 组件的 `onCollapse` 回调同步状态。`MenuLayout` 还负责渲染折叠/展开的触发图标(`MenuUnfoldOutlined`/`MenuFoldOutlined`),实现了完整的交互体验。 + +**本节来源** +- [Menu/Layout/index.tsx](file://datavines-ui/src/component/Menu/Layout/index.tsx#L17-L20) +- [Menu/Layout/index.tsx](file://datavines-ui/src/component/Menu/Layout/index.tsx#L34-L38) + +### Layout 布局容器分析 +`MenuLayout` 组件基于 Ant Design 的 `Layout` 组件构建,实现了经典的侧边栏-内容布局。 + +#### 响应式设计 +组件通过设置 `Sider` 的 `style` 属性为 `height: '100vh'` 和 `overflow: 'auto'`,确保侧边栏高度占满视口且内容可滚动。`Content` 区域由 `MenuLayout` 的 `children` prop 填充,实现了内容的灵活嵌入。整个布局结构清晰,易于维护和扩展。 + +#### 嵌套结构 +`MenuLayout` 采用嵌套的 `Layout` 组件结构,外层 `Layout` 包含一个 `Layout` 子元素,该子元素再包含 `Sider` 和另一个 `Layout`。这种嵌套方式是 Ant Design 推荐的经典布局模式,能够精确控制侧边栏和内容区域的布局关系。 + +**本节来源** +- [Menu/Layout/index.tsx](file://datavines-ui/src/component/Menu/Layout/index.tsx#L25-L53) + +### ContentLayout 内容区域分析 +`ContentLayout` 是一个简单的函数式组件,主要作用是为内容区域提供统一的样式。 + +#### 自适应填充机制 +组件通过设置 `height: height || '100vh'` 实现高度自适应,默认占满整个视口高度。`overflowY: 'auto'` 确保内容超出时可垂直滚动。`padding` 属性设置了内边距,优化了内容的视觉呈现。组件通过 `style` prop 接收外部样式,实现了样式的可扩展性。 + +**本节来源** +- [ContentLayout/index.tsx](file://datavines-ui/src/component/ContentLayout/index.tsx#L9-L20) + +## 依赖分析 +布局组件依赖于多个核心库和内部模块。 + +```mermaid +graph TD +A[MenuLayout] --> B[Ant Design Layout] +A --> C[Ant Design Icons] +A --> D[MenuAside] +A --> E[Header] +D --> F[Ant Design Menu] +D --> G[Ant Design Popover] +D --> H[React Router] +D --> I[Redux Store] +D --> J[utils/constants] +E --> K[Logo] +E --> L[WorkSpaceSwitch] +E --> M[Settings] +I --> N[DV_STORAGE_LOGIN] +I --> O[DV_LANGUAGE] +I --> P[DV_WORKSPACE_ID] +``` + +**图示来源** +- [Menu/Layout/index.tsx](file://datavines-ui/src/component/Menu/Layout/index.tsx#L2-L5) +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx#L3-L6) +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx#L16) +- [Header/index.tsx](file://datavines-ui/src/component/Header/index.tsx#L2-L4) +- [utils/constants.ts](file://datavines-ui/src/utils/constants.ts#L6-L8) + +**本节来源** +- [Menu/Layout/index.tsx](file://datavines-ui/src/component/Menu/Layout/index.tsx#L1-L57) +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx#L1-L237) +- [Header/index.tsx](file://datavines-ui/src/component/Header/index.tsx#L1-L16) +- [utils/constants.ts](file://datavines-ui/src/utils/constants.ts#L1-L9) + +## 性能考虑 +- **懒加载**:路由组件通过 `React.lazy` 实现代码分割,减少初始加载体积。 +- **状态优化**:`MenuAside` 使用 `useCallback` 和 `useMemo`(通过 `useWatch`)优化回调函数和副作用,避免不必要的重新渲染。 +- **组件拆分**:UI 组件被拆分为多个小的、可复用的组件(如 `Logo`、`WorkSpaceSwitch`),符合单一职责原则,有利于性能优化和维护。 + +## 故障排除指南 +- **菜单不显示**:检查 `menus` prop 是否正确传递,确认路由配置中的 `menuHide` 属性。 +- **路由不匹配**:检查 `mainRouter.tsx` 中的 `path` 是否与实际 URL 一致,特别是动态参数 `:id` 的处理。 +- **状态不更新**:确认 Redux Store 中的状态是否正确更新,检查 `useSelector` 的依赖项。 +- **样式问题**:检查 `ContentLayout` 的 `height` 和 `padding` 是否被覆盖,确认 `Sider` 的 `style` 属性。 + +**本节来源** +- [Menu/MenuAside/index.tsx](file://datavines-ui/src/component/Menu/MenuAside/index.tsx#L48-L56) +- [router/mainRouter.tsx](file://datavines-ui/src/router/mainRouter.tsx#L9-L34) +- [store/rootReducer.ts](file://datavines-ui/src/store/rootReducer.ts#L1-L26) +- [ContentLayout/index.tsx](file://datavines-ui/src/component/ContentLayout/index.tsx#L11-L14) + +## 结论 +DataVines 的布局组件设计精良,结构清晰,充分运用了 React 生态系统的最佳实践。通过 `MenuLayout`、`MenuAside` 和 `ContentLayout` 的协同工作,构建了一个功能完整、交互流畅的管理后台界面。组件间的职责分离、状态管理的集中化以及路由配置的灵活性,为系统的可维护性和可扩展性奠定了坚实基础。建议在开发新页面时遵循现有模式,确保 UI 风格和交互逻辑的一致性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/\351\200\232\347\224\250\347\273\204\344\273\266.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/\351\200\232\347\224\250\347\273\204\344\273\266.md" new file mode 100644 index 00000000..f0946cc1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/UI\347\273\204\344\273\266\347\263\273\347\273\237/\351\200\232\347\224\250\347\273\204\344\273\266.md" @@ -0,0 +1,281 @@ +# 通用组件 + + +**本文档引用的文件** +- [Header/index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [Header/index.less](file://datavines-ui\src\component\Header\index.less) +- [SearchForm/index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [SearchForm/index.less](file://datavines-ui\src\component\SearchForm\index.less) +- [Title/index.tsx](file://datavines-ui\src\component\Title\index.tsx) +- [Title/index.less](file://datavines-ui\src\component\Title\index.less) +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) +- [GoBack/index.tsx](file://datavines-ui\src\component\GoBack\index.tsx) +- [Header/Settings/index.tsx](file://datavines-ui\src\component\Header\Settings\index.tsx) +- [Header/WorkSpaceSwitch/index.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\index.tsx) + + +## 目录 +1. [引言](#引言) +2. [页头组件设计](#页头组件设计) +3. [搜索表单实现](#搜索表单实现) +4. [标题栏动态渲染](#标题栏动态渲染) +5. [缓存组件原理](#缓存组件原理) +6. [组件通信与状态管理](#组件通信与状态管理) +7. [性能优化建议](#性能优化建议) +8. [使用示例](#使用示例) +9. [结论](#结论) + +## 引言 +本文档详细描述了Datavines项目中通用UI组件的设计与实现。重点分析了页头(Header)、搜索表单(SearchForm)、标题栏(Title)和缓存(KeepAlive)等核心组件的架构设计、实现原理和使用方法。这些组件构成了系统用户界面的基础,提供了统一的视觉风格和交互模式。 + +## 页头组件设计 + +页头组件(Header)是系统的主要导航区域,包含Logo、工作区切换和用户设置等功能模块。组件采用React函数式组件实现,通过Flex布局组织各个子组件。 + +```mermaid +classDiagram +class Header { ++render() JSX.Element +} +class Logo { ++style : CSSProperties ++render() JSX.Element +} +class WorkSpaceSwitch { ++render() JSX.Element +} +class Settings { ++render() JSX.Element +} +Header --> Logo : 包含 +Header --> WorkSpaceSwitch : 包含 +Header --> Settings : 包含 +``` + +**图示来源** +- [Header/index.tsx](file://datavines-ui\src\component\Header\index.tsx#L7-L15) +- [Header/Logo/index.tsx](file://datavines-ui\src\component\Header\Logo\index.tsx) +- [Header/WorkSpaceSwitch/index.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\index.tsx) +- [Header/Settings/index.tsx](file://datavines-ui\src\component\Header\Settings\index.tsx) + +页头组件的主要特性包括: +- 响应式布局,适应不同屏幕尺寸 +- 模块化设计,各功能组件独立可复用 +- 使用Ant Design组件库确保UI一致性 +- 支持国际化文本显示 + +**组件来源** +- [Header/index.tsx](file://datavines-ui\src\component\Header\index.tsx#L1-L15) + +## 搜索表单实现 + +搜索表单(SearchForm)组件实现了受控组件模式,封装了Ant Design的Form和Input组件,提供统一的搜索界面。 + +```mermaid +sequenceDiagram +participant 用户 +participant SearchForm +participant AntForm +participant 回调函数 +用户->>SearchForm : 输入搜索关键词 +SearchForm->>AntForm : 获取表单值 +AntForm-->>SearchForm : 返回字段值 +SearchForm->>回调函数 : 调用onSearch +回调函数-->>SearchForm : 处理搜索逻辑 +SearchForm-->>用户 : 显示搜索结果 +``` + +**图示来源** +- [SearchForm/index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx#L12-L43) + +搜索表单的主要props接口定义如下: + +| 属性 | 类型 | 默认值 | 描述 | +|------|------|--------|------| +| onSearch | (val: string) => void | 必需 | 搜索回调函数 | +| form | FormInstance | 可选 | 表单实例,外部传入或内部创建 | +| placeholder | string | 可选 | 输入框占位符文本 | + +组件采用受控组件模式,通过`useMemo`和`Form.useForm()`实现表单实例的管理。当外部传入form实例时使用传入的实例,否则创建新的表单实例。 + +**组件来源** +- [SearchForm/index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx#L6-L43) + +## 标题栏动态渲染 + +标题栏(Title)组件实现了动态渲染机制,根据是否需要显示返回按钮来调整样式和布局。 + +```mermaid +flowchart TD +Start([组件初始化]) --> CheckBack{"isBack属性?"} +CheckBack --> |true| RenderWithBack["渲染返回按钮和内容"] +CheckBack --> |false| RenderWithoutBack["仅渲染内容"] +RenderWithBack --> ApplyStyle["应用dv-title样式"] +RenderWithoutBack --> ApplyNoBackStyle["应用dv-title_noback样式"] +ApplyNoBackStyle --> AddLeftBar["添加左侧标识条"] +ApplyStyle --> End([渲染完成]) +AddLeftBar --> End +``` + +**图示来源** +- [Title/index.tsx](file://datavines-ui\src\component\Title\index.tsx#L5-L12) +- [Title/index.less](file://datavines-ui\src\component\Title\index.less) + +标题栏组件支持以下props: +- `isBack`: boolean类型,控制是否显示返回按钮 +- `children`: React.ReactNode类型,标题内容 + +当`isBack`为true时,组件左侧显示返回按钮;为false时,左侧显示彩色标识条,增强视觉层次。 + +**组件来源** +- [Title/index.tsx](file://datavines-ui\src\component\Title\index.tsx#L5-L12) + +## 缓存组件原理 + +KeepAlive组件实现了路由级别的组件缓存功能,通过React Portal和引用管理来保持组件状态。 + +```mermaid +classDiagram +class KeepAlive { +-containerRef : RefObject +-components : RefObject> +-update : Function ++render() JSX.Element +} +class Component { +-targetElement : HTMLDivElement +-activatedRef : RefObject ++render() JSX.Element +} +class KeepAliveContext { ++destroy : (params : string, render? : boolean) => void ++isActive : boolean +} +KeepAlive --> Component : 渲染多个实例 +KeepAlive --> KeepAliveContext : 提供上下文 +Component --> ReactDOM.createPortal : 渲染到指定容器 +``` + +**图示来源** +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx#L34-L113) + +缓存组件的核心原理: +1. 使用`useRef`存储组件实例数组,避免重新渲染 +2. 通过`useLocation`获取当前路由路径作为缓存键 +3. 利用`ReactDOM.createPortal`将非激活组件渲染到隐藏容器中 +4. 提供`destroy`方法用于手动清除特定路由的缓存 + +组件支持以下配置属性: +- `include`: string[],指定需要缓存的路由 +- `exclude`: string[],指定不需要缓存的路由 +- `maxLen`: number,默认5,缓存最大数量 +- `children`: 被缓存的组件 + +**组件来源** +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx#L34-L113) + +## 组件通信与状态管理 + +系统采用Redux进行全局状态管理,各组件通过useSelector和useActions进行状态读取和更新。 + +```mermaid +graph TD +A[Header] --> |读取用户信息| B(Redux Store) +C[WorkSpaceSwitch] --> |读取工作区| B +D[Settings] --> |读取语言设置| B +E[KeepAlive] --> |监听路由变化| F(useLocation) +F --> |提供路径信息| E +G[SearchForm] --> |触发搜索| H(回调函数) +H --> |更新状态| B +B --> |状态变化| I[视图更新] +``` + +**图示来源** +- [Header/Settings/index.tsx](file://datavines-ui\src\component\Header\Settings\index.tsx#L9) +- [Header/WorkSpaceSwitch/index.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\index.tsx#L11) +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx#L18) + +主要状态管理策略: +- 使用Redux管理用户登录信息、工作区选择等全局状态 +- 通过React Context传递KeepAlive组件的缓存控制方法 +- 利用React Router的hooks监听路由变化 +- 使用自定义hooks封装常用状态逻辑 + +**组件来源** +- [Header/Settings/index.tsx](file://datavines-ui\src\component\Header\Settings\index.tsx) +- [Header/WorkSpaceSwitch/index.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\index.tsx) +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) + +## 性能优化建议 + +基于组件实现分析,提出以下性能优化建议: + +### 虚拟滚动 +对于包含大量数据的列表组件,建议实现虚拟滚动,只渲染可视区域内的元素,显著提升渲染性能。 + +### 懒加载 +对非首屏显示的组件采用懒加载策略,使用React.lazy和Suspense实现代码分割,减少初始加载时间。 + +### 防抖处理 +在搜索表单等频繁触发的交互场景中,建议添加防抖处理,避免过于频繁的请求调用。 + +```mermaid +flowchart LR +A[用户输入] --> B{是否停止输入?} +B --> |否| C[等待300ms] +C --> B +B --> |是| D[触发搜索请求] +D --> E[更新搜索结果] +``` + +**图示来源** +- [SearchForm/index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) + +其他优化建议: +- 使用React.memo对纯展示组件进行记忆化 +- 避免在render方法中创建新对象或函数 +- 合理使用key属性优化列表渲染 +- 对复杂计算使用useMemo进行缓存 + +**组件来源** +- [SearchForm/index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) + +## 使用示例 + +### 页头组件使用 +```jsx +
+``` + +### 搜索表单使用 +```jsx + +``` + +### 标题栏使用 +```jsx +数据源管理 +系统设置 +``` + +### 缓存组件使用 +```jsx + + + + +``` + +这些组件在实际业务场景中被广泛使用,如数据源管理页面使用搜索表单进行过滤,详情页面使用带返回按钮的标题栏等。 + +**组件来源** +- [Header/index.tsx](file://datavines-ui\src\component\Header\index.tsx) +- [SearchForm/index.tsx](file://datavines-ui\src\component\SearchForm\index.tsx) +- [Title/index.tsx](file://datavines-ui\src\component\Title\index.tsx) +- [KeepAlive.tsx](file://datavines-ui\src\component\KeepAlive.tsx) + +## 结论 +本文档详细分析了Datavines项目中的核心UI组件设计与实现。这些组件采用模块化设计,具有良好的复用性和扩展性。通过合理的状态管理和性能优化策略,确保了系统的响应速度和用户体验。建议在实际开发中遵循组件的使用规范,充分利用其提供的功能特性,同时根据具体业务需求进行适当的定制和优化。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/datavines-ui\346\250\241\345\235\227.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/datavines-ui\346\250\241\345\235\227.md" new file mode 100644 index 00000000..58fa21c7 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/datavines-ui\346\250\241\345\235\227.md" @@ -0,0 +1,462 @@ +# datavines-ui模块 + + +**本文档引用的文件** +- [package.json](file://datavines-ui/package.json) +- [src/index.tsx](file://datavines-ui/src/index.tsx) +- [src/App/index.tsx](file://datavines-ui/src/App/index.tsx) +- [src/router/index.tsx](file://datavines-ui/src/router/index.tsx) +- [src/router/mainRouter.tsx](file://datavines-ui/src/router/mainRouter.tsx) +- [src/store/index.ts](file://datavines-ui/src/store/index.ts) +- [src/store/rootReducer.ts](file://datavines-ui/src/store/rootReducer.ts) +- [src/view/Main/index.tsx](file://datavines-ui/src/view/Main/index.tsx) +- [src/view/Main/Home/index.tsx](file://datavines-ui/src/view/Main/Home/index.tsx) +- [src/view/Main/Warning/index.tsx](file://datavines-ui/src/view/Main/Warning/index.tsx) +- [src/view/Main/ErrorDataManage/index.tsx](file://datavines-ui/src/view/Main/ErrorDataManage/index.tsx) +- [src/view/Main/UserManage/index.tsx](file://datavines-ui/src/view/Main/UserManage/index.tsx) +- [src/view/Main/Label/index.tsx](file://datavines-ui/src/view/Main/Label/index.tsx) +- [src/component/Header/index.tsx](file://datavines-ui/src/component/Header/index.tsx) +- [src/theme/index.tsx](file://datavines-ui/src/theme/index.tsx) + + +## 目录 +1. [介绍](#介绍) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 介绍 + +datavines-ui模块是DataVines数据质量平台的前端用户界面,基于React技术栈构建。该模块为用户提供直观的可视化界面,用于管理数据源、配置数据质量任务、监控任务执行状态以及查看质量报告。系统采用现代化的前端架构,包括React组件化开发、Redux状态管理、React Router路由控制以及Ant Design UI组件库,为用户提供流畅的操作体验。 + +**本文档引用的文件** +- [package.json](file://datavines-ui/package.json) + +## 项目结构 + +datavines-ui模块采用标准的React前端项目结构,主要包含以下目录: + +- **build**: Webpack构建配置文件,包含开发和生产环境的配置 +- **public**: 静态资源文件,如HTML模板 +- **src**: 源代码目录,包含应用的主要逻辑 + - **App**: 应用根组件和配置提供者 + - **action**: Redux动作定义 + - **common**: 通用工具函数和组件 + - **component**: 可复用的UI组件 + - **hooks**: 自定义React Hooks + - **http**: HTTP请求封装 + - **locale**: 国际化支持 + - **router**: 路由配置 + - **store**: Redux状态管理 + - **theme**: 主题配置 + - **type**: TypeScript类型定义 + - **view**: 页面视图组件 +- **Editor**: 编辑器相关组件和工具 +- **typings**: 类型定义文件 + +```mermaid +graph TD +A[datavines-ui] --> B[build] +A --> C[public] +A --> D[src] +A --> E[Editor] +A --> F[typings] +D --> G[App] +D --> H[action] +D --> I[common] +D --> J[component] +D --> K[hooks] +D --> L[http] +D --> M[locale] +D --> N[router] +D --> O[store] +D --> P[theme] +D --> Q[type] +D --> R[view] +``` + +**本文档引用的文件** +- [package.json](file://datavines-ui/package.json) + +## 核心组件 + +datavines-ui模块的核心组件包括应用入口、路由系统、状态管理和UI组件。应用使用React 18作为基础框架,通过React Router实现客户端路由,Redux进行全局状态管理,并采用Ant Design作为UI组件库。模块还集成了Monaco Editor用于代码编辑,ECharts用于数据可视化。 + +**本文档引用的文件** +- [package.json](file://datavines-ui/package.json) +- [src/index.tsx](file://datavines-ui/src/index.tsx) +- [src/App/index.tsx](file://datavines-ui/src/App/index.tsx) + +## 架构概述 + +datavines-ui模块采用分层架构设计,主要包括表现层、逻辑层和数据层。表现层由React组件构成,负责用户界面的展示;逻辑层包含业务逻辑和状态管理;数据层处理与后端API的通信。 + +```mermaid +graph TB +subgraph "表现层" +A[React组件] +B[Ant Design UI] +C[Monaco Editor] +D[ECharts] +end +subgraph "逻辑层" +E[React Router] +F[Redux Store] +G[自定义Hooks] +end +subgraph "数据层" +H[HTTP Client] +I[API服务] +end +A --> E +B --> A +C --> A +D --> A +E --> F +F --> G +G --> H +H --> I +``` + +**本文档引用的文件** +- [src/App/index.tsx](file://datavines-ui/src/App/index.tsx) +- [src/router/index.tsx](file://datavines-ui/src/router/index.tsx) +- [src/store/index.ts](file://datavines-ui/src/store/index.ts) + +## 详细组件分析 + +### React组件架构 + +datavines-ui模块采用组件化开发模式,将UI分解为可复用的独立组件。主要组件包括布局组件、表单组件、表格组件和模态框组件等。组件之间通过props进行数据传递,使用React Hooks管理组件内部状态。 + +```mermaid +classDiagram +class LayoutComponent { ++Header ++MenuLayout ++ContentLayout +} +class FormComponent { ++SearchForm ++CustomSelect ++FormRender +} +class TableComponent { ++CardList ++TableList ++SqlTable +} +class ModalComponent { ++PopConfirm ++useModal ++useAddDataSource +} +LayoutComponent --> FormComponent : "包含" +LayoutComponent --> TableComponent : "包含" +LayoutComponent --> ModalComponent : "包含" +``` + +**本文档引用的文件** +- [src/component/Header/index.tsx](file://datavines-ui/src/component/Header/index.tsx) +- [src/view/Main/Home/index.tsx](file://datavines-ui/src/view/Main/Home/index.tsx) + +### 路由管理 + +datavines-ui模块使用React Router进行路由管理,实现了基于哈希的路由模式。路由配置分为登录前路由和主应用路由两部分,通过懒加载优化初始加载性能。 + +```mermaid +graph TD +A[根路由] --> B[登录路由] +A --> C[主应用路由] +B --> D[/login] +B --> E[/register] +B --> F[/forgetPwd] +C --> G[/main/home] +C --> H[/main/warning] +C --> I[/main/errorDataManage] +C --> J[/main/userManage] +C --> K[/main/label] +C --> L[/main/config] +C --> M[/main/tokenManager] +``` + +**本文档引用的文件** +- [src/router/index.tsx](file://datavines-ui/src/router/index.tsx) +- [src/router/mainRouter.tsx](file://datavines-ui/src/router/mainRouter.tsx) + +### 状态管理 + +datavines-ui模块采用Redux进行全局状态管理,将应用状态分为多个reducer,包括用户状态、通用状态、工作空间状态和数据源状态。通过Redux Thunk处理异步操作,Redux Logger在开发环境提供状态变更日志。 + +```mermaid +classDiagram +class Store { ++createStore() ++applyMiddleware() +} +class Reducer { ++userReducer ++commonReducer ++workSpaceReducer ++datasourceReducer +} +class Middleware { ++thunk ++logger +} +Store --> Reducer : "包含" +Store --> Middleware : "应用" +Reducer --> userReducer +Reducer --> commonReducer +Reducer --> workSpaceReducer +Reducer --> datasourceReducer +``` + +**本文档引用的文件** +- [src/store/index.ts](file://datavines-ui/src/store/index.ts) +- [src/store/rootReducer.ts](file://datavines-ui/src/store/rootReducer.ts) + +### API交互 + +datavines-ui模块通过封装的HTTP客户端与后端API进行交互。使用Axios作为HTTP客户端库,实现了请求和响应拦截器,统一处理认证、错误和加载状态。 + +```mermaid +sequenceDiagram +participant UI as "UI组件" +participant Hook as "自定义Hooks" +participant HTTP as "HTTP客户端" +participant API as "后端API" +UI->>Hook : 调用usePersistFn +Hook->>HTTP : 发起API请求 +HTTP->>HTTP : 请求拦截器(添加认证) +HTTP->>API : 发送HTTP请求 +API-->>HTTP : 返回响应 +HTTP->>HTTP : 响应拦截器(处理错误) +HTTP-->>Hook : 返回数据 +Hook-->>UI : 更新状态 +``` + +**本文档引用的文件** +- [src/http/index.ts](file://datavines-ui/src/http/index.ts) +- [src/view/Main/Home/index.tsx](file://datavines-ui/src/view/Main/Home/index.tsx) + +### 主要页面分析 + +#### 数据源管理页面 + +数据源管理页面提供数据源的列表展示、创建、编辑和删除功能。支持卡片和表格两种视图模式,用户可以根据偏好切换。 + +```mermaid +flowchart TD +Start([进入数据源管理]) --> Load["加载数据源列表"] +Load --> Display{"选择视图模式"} +Display --> |卡片视图| CardView["显示卡片布局"] +Display --> |表格视图| TableView["显示表格布局"] +CardView --> Action["支持操作: 查看详情、编辑、删除"] +TableView --> Action +Action --> Create["创建新数据源"] +Create --> Form["填写数据源表单"] +Form --> Save["保存并刷新列表"] +Save --> End([返回列表]) +``` + +**本文档引用的文件** +- [src/view/Main/Home/index.tsx](file://datavines-ui/src/view/Main/Home/index.tsx) + +#### 任务配置页面 + +任务配置页面允许用户创建和管理数据质量检查任务。通过表单界面收集任务配置参数,支持多种数据源和检查规则。 + +```mermaid +flowchart TD +A([任务配置入口]) --> B[选择数据源] +B --> C[选择检查指标] +C --> D[配置检查参数] +D --> E[设置调度计划] +E --> F[配置通知方式] +F --> G[保存任务配置] +G --> H[验证配置] +H --> I{验证成功?} +I --> |是| J[任务创建成功] +I --> |否| K[显示错误信息] +K --> D +``` + +**本文档引用的文件** +- [src/view/Main/Config/index.tsx](file://datavines-ui/src/view/Main/Config/index.tsx) + +#### 执行监控页面 + +执行监控页面实时展示任务执行状态和日志,帮助用户了解任务运行情况。 + +```mermaid +flowchart TD +A([执行监控]) --> B[获取任务实例列表] +B --> C[选择任务实例] +C --> D[加载执行日志] +D --> E[显示执行进度] +E --> F[监控执行状态] +F --> G{任务完成?} +G --> |否| H[轮询更新状态] +G --> |是| I[显示最终结果] +I --> J[分析执行报告] +``` + +**本文档引用的文件** +- [src/view/Main/HomeDetail/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/index.tsx) + +#### 质量报告页面 + +质量报告页面可视化展示数据质量检查结果,提供详细的指标分析和趋势图表。 + +```mermaid +flowchart TD +A([质量报告]) --> B[选择时间范围] +B --> C[获取质量数据] +C --> D[生成质量趋势图] +D --> E[计算质量评分] +E --> F[分析异常数据] +F --> G[生成详细报告] +G --> H[导出报告] +``` + +**本文档引用的文件** +- [src/view/Main/HomeDetail/Dashboard/qualityReportDashboard/index.tsx](file://datavines-ui/src/view/Main/HomeDetail/Dashboard/qualityReportDashboard/index.tsx) + +### Ant Design组件使用 + +datavines-ui模块广泛使用Ant Design组件库,包括按钮、表单、表格、模态框、通知等UI组件。通过按需加载和主题定制,优化了组件的使用效率和视觉一致性。 + +```mermaid +classDiagram +class AntDesignComponent { ++Button ++Form ++Table ++Modal ++Message ++Notification ++Spin ++Radio ++Input +} +class CustomComponent { ++SearchForm ++ContentLayout ++Title ++GoBack +} +AntDesignComponent --> CustomComponent : "基础" +CustomComponent --> datavines-ui : "应用" +``` + +**本文档引用的文件** +- [package.json](file://datavines-ui/package.json) +- [src/component/index.tsx](file://datavines-ui/src/component/index.tsx) + +### 自定义主题配置 + +datavines-ui模块支持自定义主题配置,通过CSS变量实现主题的动态切换。主题配置包括颜色、字体、间距等设计系统元素。 + +```mermaid +classDiagram +class ThemeConfig { ++setTheme() ++useSetTheme() +} +ThemeConfig --> CSS : "设置CSS变量" +CSS --> Document : "应用到文档根元素" +Document --> UI : "影响所有组件样式" +``` + +**本文档引用的文件** +- [src/theme/index.tsx](file://datavines-ui/src/theme/index.tsx) + +## 依赖分析 + +datavines-ui模块的依赖关系清晰,主要依赖包括React生态、UI组件库、状态管理、HTTP客户端和开发工具。 + +```mermaid +graph TD +A[datavines-ui] --> B[React] +A --> C[Ant Design] +A --> D[Redux] +A --> E[Axios] +A --> F[Webpack] +A --> G[TypeScript] +A --> H[Monaco Editor] +A --> I[ECharts] +A --> J[ahooks] +B --> K[React DOM] +B --> L[React Router] +C --> M[@ant-design/icons] +D --> N[Redux Thunk] +D --> O[Redux Logger] +F --> P[webpack-dev-server] +F --> Q[html-webpack-plugin] +``` + +**本文档引用的文件** +- [package.json](file://datavines-ui/package.json) + +## 性能考虑 + +datavines-ui模块在性能优化方面采取了多项措施,包括代码分割、懒加载、组件优化和缓存策略,确保应用的流畅运行。 + +### 前端开发环境搭建 + +datavines-ui模块使用Webpack作为构建工具,支持开发和生产两种环境配置。开发环境提供热重载和调试工具,生产环境进行代码压缩和优化。 + +### 构建部署 + +通过npm scripts提供标准化的构建命令,支持测试环境和生产环境的构建。 + +### 自定义UI组件开发 + +模块提供了丰富的自定义Hook和工具函数,支持快速开发新的UI组件。 + +### 性能优化最佳实践 + +- 使用React.memo优化组件渲染 +- 采用懒加载减少初始加载时间 +- 使用虚拟滚动处理大数据量列表 +- 实现请求缓存减少重复API调用 + +### 用户体验改进 + +- 提供加载状态反馈 +- 实现表单验证和错误提示 +- 支持国际化和多语言 +- 优化移动端适配 + +**本文档引用的文件** +- [package.json](file://datavines-ui/package.json) +- [build/webpack.common.js](file://datavines-ui/build/webpack.common.js) + +## 故障排除指南 + +### 常见问题 + +1. **页面空白**: 检查控制台错误,确认依赖安装完整 +2. **API调用失败**: 检查后端服务是否正常运行,确认跨域配置 +3. **样式丢失**: 确认CSS文件正确加载,检查Webpack配置 +4. **状态更新异常**: 检查Redux action和reducer逻辑 + +### 调试工具 + +- React DevTools: 检查组件树和状态 +- Redux DevTools: 跟踪状态变更 +- 浏览器开发者工具: 调试网络请求和JavaScript错误 + +**本文档引用的文件** +- [src/App/index.tsx](file://datavines-ui/src/App/index.tsx) +- [src/store/index.ts](file://datavines-ui/src/store/index.ts) + +## 结论 + +datavines-ui模块作为DataVines平台的前端界面,提供了完整的数据质量管理功能。通过现代化的前端技术栈和良好的架构设计,实现了高性能、易维护的用户界面。模块具有良好的扩展性,支持未来功能的持续迭代和优化。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\211\215\347\253\257\346\236\266\346\236\204\350\256\276\350\256\241.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\211\215\347\253\257\346\236\266\346\236\204\350\256\276\350\256\241.md" new file mode 100644 index 00000000..41a5d014 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\211\215\347\253\257\346\236\266\346\236\204\350\256\276\350\256\241.md" @@ -0,0 +1,426 @@ +# 前端架构设计 + + +**本文档引用的文件** +- [package.json](file://datavines-ui/package.json) +- [index.tsx](file://datavines-ui/src/index.tsx) +- [App/index.tsx](file://datavines-ui/src/App/index.tsx) +- [router/index.tsx](file://datavines-ui/src/router/index.tsx) +- [router/mainRouter.tsx](file://datavines-ui/src/router/mainRouter.tsx) +- [store/index.ts](file://datavines-ui/src/store/index.ts) +- [store/rootReducer.ts](file://datavines-ui/src/store/rootReducer.ts) +- [store/commonReducer/index.ts](file://datavines-ui/src/store/commonReducer/index.ts) +- [store/userReducer/index.ts](file://datavines-ui/src/store/userReducer/index.ts) +- [http/index.ts](file://datavines-ui/src/http/index.ts) +- [theme/index.tsx](file://datavines-ui/src/theme/index.tsx) +- [locale/index.tsx](file://datavines-ui/src/locale/index.tsx) +- [locale/zh_CN.ts](file://datavines-ui/src/locale/zh_CN.ts) +- [locale/en_US.ts](file://datavines-ui/src/locale/en_US.ts) +- [App/ConfigProvider.tsx](file://datavines-ui/src/App/ConfigProvider.tsx) +- [view/Main/index.tsx](file://datavines-ui/src/view/Main/index.tsx) +- [Editor/http/response.interceptor.ts](file://datavines-ui/Editor/http/response.interceptor.ts) +- [src/preset.ts](file://datavines-ui/src/preset.ts) + + +## 目录 +1. [项目结构](#项目结构) +2. [应用启动流程](#应用启动流程) +3. [路由管理](#路由管理) +4. [状态管理](#状态管理) +5. [HTTP请求封装](#http请求封装) +6. [主题定制方案](#主题定制方案) +7. [国际化实现](#国际化实现) +8. [代码组织结构与模块依赖](#代码组织结构与模块依赖) +9. [架构决策考量](#架构决策考量) +10. [性能优化策略](#性能优化策略) + +## 项目结构 + +datavines-ui前端项目采用基于React+Ant Design的组件化架构,项目结构清晰,模块划分明确。主要目录包括: +- `src`: 源代码目录,包含应用的核心代码 +- `src/App`: 应用根组件和配置提供者 +- `src/component`: 通用UI组件 +- `src/hooks`: 自定义React Hooks +- `src/http`: HTTP请求封装 +- `src/locale`: 国际化语言包 +- `src/router`: 路由配置 +- `src/store`: Redux状态管理 +- `src/theme`: 主题定制 +- `src/view`: 页面视图组件 +- `src/utils`: 工具函数 +- `Editor/http`: 编辑器HTTP拦截器(新增) + +**Section sources** +- [package.json](file://datavines-ui/package.json) + +## 应用启动流程 + +datavines-ui应用的启动流程从`src/index.tsx`文件开始,通过React的createRoot方法将应用挂载到DOM节点上。应用启动时会进行以下初始化操作: +1. 创建React根节点并挂载到id为"root"的DOM元素 +2. 使用Suspense组件包裹应用,提供加载状态的fallback +3. 通过Provider组件将Redux store注入到应用中 +4. 初始化国际化和主题配置 + +应用启动流程体现了React应用的标准启动模式,确保了应用的稳定性和可维护性。 + +```mermaid +flowchart TD +Start([应用启动]) --> CreateRoot["创建React根节点"] +CreateRoot --> MountDOM["挂载到DOM"] +MountDOM --> InitializeProvider["初始化Provider"] +InitializeProvider --> InjectStore["注入Redux Store"] +InjectStore --> InitializeIntl["初始化国际化"] +InitializeIntl --> InitializeTheme["初始化主题"] +InitializeTheme --> AppReady["应用准备就绪"] +``` + +**Diagram sources** +- [index.tsx](file://datavines-ui/src/index.tsx) +- [App/index.tsx](file://datavines-ui/src/App/index.tsx) + +**Section sources** +- [index.tsx](file://datavines-ui/src/index.tsx) +- [App/index.tsx](file://datavines-ui/src/App/index.tsx) + +## 路由管理 + +datavines-ui使用react-router-dom进行路由管理,采用HashRouter模式,确保在不同部署环境下路由的稳定性。路由配置分为登录前路由和主应用路由两部分: + +1. **登录前路由**:包含登录、注册、忘记密码等不需要认证的页面 +2. **主应用路由**:包含数据源管理、告警管理、用户管理等需要认证的功能模块 + +路由配置采用了懒加载模式,通过React.lazy和import()语法实现代码分割,优化了应用的初始加载性能。 + +```mermaid +classDiagram +class Router { ++HashRouter as Router ++Route ++Switch ++Redirect +} +class RouteConfig { ++path : string ++component : React.ComponentType ++exact? : boolean ++menuHide? : boolean +} +class RouterManager { +-routerNoLogin : RouteConfig[] +-mainRouter : RouteConfig[] ++generateRoute() : JSX.Element[] +} +Router --> RouterManager : "使用" +RouterManager --> RouteConfig : "包含" +``` + +**Diagram sources** +- [App/index.tsx](file://datavines-ui/src/App/index.tsx) +- [router/index.tsx](file://datavines-ui/src/router/index.tsx) +- [router/mainRouter.tsx](file://datavines-ui/src/router/mainRouter.tsx) + +**Section sources** +- [App/index.tsx](file://datavines-ui/src/App/index.tsx) +- [router/index.tsx](file://datavines-ui/src/router/index.tsx) +- [router/mainRouter.tsx](file://datavines-ui/src/router/mainRouter.tsx) + +## 状态管理 + +datavines-ui采用Redux作为状态管理方案,结合Redux Thunk中间件处理异步操作。状态管理架构包括: + +1. **Store创建**:使用createStore创建Redux store,结合combineReducers管理多个reducer +2. **Middleware配置**:在开发环境中使用redux-logger记录状态变化,在生产环境中仅使用redux-thunk处理异步操作 +3. **DevTools集成**:在开发环境中集成Redux DevTools Extension,便于调试状态变化 + +状态管理模块包括多个reducer,分别管理用户信息、通用状态、工作空间和数据源等不同领域的状态。 + +```mermaid +classDiagram +class Store { ++createStore() ++applyMiddleware() ++composeWithDevTools() +} +class Middleware { ++thunk ++logger +} +class Reducer { ++userReducer ++commonReducer ++workSpaceReducer ++datasourceReducer +} +class Action { ++type : string ++payload : any +} +Store --> Middleware : "应用" +Store --> Reducer : "包含" +Reducer --> Action : "处理" +``` + +**Diagram sources** +- [store/index.ts](file://datavines-ui/src/store/index.ts) +- [store/rootReducer.ts](file://datavines-ui/src/store/rootReducer.ts) +- [store/commonReducer/index.ts](file://datavines-ui/src/store/commonReducer/index.ts) +- [store/userReducer/index.ts](file://datavines-ui/src/store/userReducer/index.ts) + +**Section sources** +- [store/index.ts](file://datavines-ui/src/store/index.ts) +- [store/rootReducer.ts](file://datavines-ui/src/store/rootReducer.ts) +- [store/commonReducer/index.ts](file://datavines-ui/src/store/commonReducer/index.ts) +- [store/userReducer/index.ts](file://datavines-ui/src/store/userReducer/index.ts) + +## HTTP请求封装 + +datavines-ui通过axios封装HTTP请求,提供了统一的请求拦截器和响应拦截器,确保请求的安全性和一致性。HTTP请求封装的主要特性包括: + +1. **基础配置**:设置API基础URL为"/api/v1" +2. **请求拦截器**:在请求头中添加认证令牌和语言信息,同时设置HTTP错误消息的国际化语言 +3. **响应拦截器**:处理认证过期、令牌刷新等特殊情况,新增完整的HTTP错误消息翻译支持 +4. **历史管理**:集成createHashHistory,便于在应用中导航 + +HTTP请求封装确保了与后端API的稳定通信,同时提供了良好的错误处理机制。 + +```mermaid +sequenceDiagram +participant Component as "组件" +participant Http as "HTTP封装" +participant Axios as "Axios实例" +participant EditorHttp as "编辑器HTTP拦截器" +participant API as "后端API" +Component->>Http : 发起请求 +Http->>Http : 请求拦截器处理 +Http->>Http : 添加认证令牌和语言头 +Http->>EditorHttp : 设置HTTP错误消息语言 +Http->>Axios : 发送请求 +Axios->>API : 实际HTTP请求 +API-->>Axios : 返回响应 +Axios-->>Http : 响应数据 +Http->>Http : 响应拦截器处理 +Http->>Http : 检查认证状态和令牌刷新 +Http->>EditorHttp : 处理HTTP错误消息翻译 +Http-->>Component : 返回处理后的数据 +``` + +**Diagram sources** +- [http/index.ts](file://datavines-ui/src/http/index.ts) +- [Editor/http/response.interceptor.ts](file://datavines-ui/Editor/http/response.interceptor.ts) + +**Section sources** +- [http/index.ts](file://datavines-ui/src/http/index.ts) +- [Editor/http/response.interceptor.ts](file://datavines-ui/Editor/http/response.interceptor.ts) + +## 主题定制方案 + +datavines-ui提供了灵活的主题定制方案,允许用户自定义应用的外观。主题定制通过CSS变量实现,主要特性包括: + +1. **动态主题设置**:通过setTheme函数动态设置CSS变量 +2. **Ant Design集成**:通过ConfigProvider组件集成Ant Design的主题配置 +3. **颜色定制**:支持自定义主色调和圆角半径 + +主题定制方案使得应用能够适应不同的品牌需求和用户偏好。 + +```mermaid +classDiagram +class ThemeManager { ++setTheme(themeObj : Record) ++useSetTheme() +} +class CSSVariables { ++--primary-color ++--border-radius +} +class AntDesignConfig { ++theme : { token : { colorPrimary, borderRadius } } ++locale ++prefixCls +} +ThemeManager --> CSSVariables : "设置" +ThemeManager --> AntDesignConfig : "集成" +``` + +**Diagram sources** +- [theme/index.tsx](file://datavines-ui/src/theme/index.tsx) +- [App/ConfigProvider.tsx](file://datavines-ui/src/App/ConfigProvider.tsx) + +**Section sources** +- [theme/index.tsx](file://datavines-ui/src/theme/index.tsx) +- [App/ConfigProvider.tsx](file://datavines-ui/src/App/ConfigProvider.tsx) + +## 国际化实现 + +datavines-ui采用react-intl实现国际化,支持中文和英文两种语言。国际化实现的主要特性包括: + +1. **语言包管理**:在`src/locale`目录下维护zh_CN和en_US两个语言包,包含完整的HTTP错误消息翻译 +2. **动态语言切换**:通过Redux状态管理当前语言,并在切换时更新UI +3. **Ant Design集成**:同步更新Ant Design组件库的语言设置 +4. **本地存储**:将用户选择的语言偏好存储在Cookie中,实现持久化 +5. **HTTP错误消息翻译**:新增完整的HTTP错误消息本地化支持,包括网络连接、超时、各种HTTP状态码的本地化消息 + +国际化实现确保了应用能够服务于不同语言的用户群体。 + +```mermaid +classDiagram +class IntlProvider { ++locale ++messages ++defaultLocale +} +class LanguageManager { ++useCommonActions().setLocale() ++chooseLocale() +} +class LanguagePack { ++zh_CN : { key : value } ++en_US : { key : value } +} +class Storage { ++Cookies.set("language") ++navigator.language +} +class HttpErrorTranslation { ++http_error_network ++http_error_timeout ++http_error_400 ++http_error_401 ++http_error_403 ++http_error_404 ++http_error_500 ++http_error_502 ++http_error_503 ++http_error_504 ++http_error_unknown +} +LanguageManager --> IntlProvider : "配置" +LanguageManager --> LanguagePack : "选择" +LanguageManager --> Storage : "持久化" +LanguagePack --> HttpErrorTranslation : "包含" +``` + +**Diagram sources** +- [locale/index.tsx](file://datavines-ui/src/locale/index.tsx) +- [locale/zh_CN.ts](file://datavines-ui/src/locale/zh_CN.ts) +- [locale/en_US.ts](file://datavines-ui/src/locale/en_US.ts) +- [store/commonReducer/index.ts](file://datavines-ui/src/store/commonReducer/index.ts) + +**Section sources** +- [locale/index.tsx](file://datavines-ui/src/locale/index.tsx) +- [locale/zh_CN.ts](file://datavines-ui/src/locale/zh_CN.ts) +- [locale/en_US.ts](file://datavines-ui/src/locale/en_US.ts) +- [store/commonReducer/index.ts](file://datavines-ui/src/store/commonReducer/index.ts) + +## 代码组织结构与模块依赖 + +datavines-ui的代码组织结构体现了清晰的模块化设计原则,各模块职责明确,依赖关系清晰。主要模块及其依赖关系如下: + +1. **核心依赖**:React、Ant Design、Redux、axios等 +2. **工具库**:ahooks、ramda、dayjs等 +3. **构建工具**:Webpack、Babel、TypeScript等 + +模块依赖关系体现了现代前端应用的典型架构,确保了代码的可维护性和可扩展性。 + +```mermaid +graph TD +A[datavines-ui] --> B[React] +A --> C[Ant Design] +A --> D[Redux] +A --> E[axios] +A --> F[ahooks] +A --> G[ramda] +A --> H[dayjs] +A --> I[Webpack] +A --> J[Babel] +A --> K[TypeScript] +B --> L[React DOM] +C --> M[Ant Design Icons] +D --> N[Redux Thunk] +D --> O[Redux Logger] +I --> P[Webpack Dev Server] +I --> Q[Mini CSS Extract Plugin] +J --> R[Babel Loader] +K --> S[TS Loader] +``` + +**Diagram sources** +- [package.json](file://datavines-ui/package.json) + +**Section sources** +- [package.json](file://datavines-ui/package.json) + +## 架构决策考量 + +在选择Redux而非Context API作为状态管理方案时,主要基于以下考量: + +1. **复杂状态管理**:应用需要管理多个领域的状态(用户、通用、工作空间、数据源等),Redux提供了更强大的状态管理能力 +2. **调试能力**:Redux DevTools提供了强大的状态变化追踪和调试功能,便于开发和问题排查 +3. **中间件支持**:Redux Thunk中间件能够优雅地处理异步操作,如API调用和令牌刷新 +4. **可预测性**:Redux的单向数据流和不可变状态更新确保了应用状态的可预测性 +5. **团队熟悉度**:Redux在团队中具有较高的熟悉度和使用经验,降低了学习成本 + +这些架构决策确保了应用的可维护性、可扩展性和开发效率。 + +**Section sources** +- [store/index.ts](file://datavines-ui/src/store/index.ts) +- [store/rootReducer.ts](file://datavines-ui/src/store/rootReducer.ts) + +## 性能优化策略 + +datavines-ui实现了多种性能优化策略,确保应用的流畅性和响应速度: + +1. **代码分割与懒加载**:通过React.lazy和import()语法实现路由级别的代码分割,减少初始加载包大小 +2. **Webpack优化**:使用TerserWebpackPlugin压缩代码,MiniCssExtractPlugin提取CSS,优化构建输出 +3. **组件优化**:使用React.memo、useCallback等Hooks避免不必要的渲染 +4. **HTTP优化**:通过请求拦截器统一处理认证信息,减少重复代码 +5. **资源管理**:使用webpack-bundle-analyzer分析包大小,持续优化依赖 + +这些性能优化策略共同确保了应用在各种设备和网络条件下的良好用户体验。 + +**Section sources** +- [App/index.tsx](file://datavines-ui/src/App/index.tsx) +- [router/index.tsx](file://datavines-ui/src/router/index.tsx) +- [package.json](file://datavines-ui/package.json) +- [webpack.common.js](file://datavines-ui/build/webpack.common.js) +- [webpack.production.js](file://datavines-ui/build/webpack.production.js) + +## HTTP错误消息翻译扩展 + +**更新** 扩展了国际化支持,新增了完整的HTTP错误消息翻译功能 + +datavines-ui在原有国际化基础上,新增了完整的HTTP错误消息翻译支持。这一扩展通过以下方式实现: + +1. **编辑器HTTP拦截器**:在`Editor/http/response.interceptor.ts`中实现了独立的HTTP错误消息翻译逻辑 +2. **多语言错误消息**:支持中文和英文两种语言的HTTP错误消息翻译 +3. **错误类型覆盖**:涵盖网络连接失败、请求超时、各种HTTP状态码(400、401、403、404、500、502、503、504)等 +4. **动态语言切换**:通过`setHttpErrorLocale`函数实现实时语言切换 +5. **与主应用集成**:在HTTP请求拦截器中自动设置当前语言环境 + +HTTP错误消息翻译的实现确保了用户在遇到各种网络和服务器错误时,都能获得准确的本地化错误提示。 + +```mermaid +flowchart TD +A[HTTP请求] --> B[请求拦截器] +B --> C[设置语言环境] +C --> D[发送请求] +D --> E[响应拦截器] +E --> F{错误类型判断} +F --> |HTTP状态码错误| G[获取对应状态码消息] +F --> |超时错误| H[获取超时消息] +F --> |网络错误| I[获取网络连接失败消息] +G --> J[返回本地化错误消息] +H --> J +I --> J +J --> K[显示错误提示] +``` + +**Diagram sources** +- [Editor/http/response.interceptor.ts](file://datavines-ui/Editor/http/response.interceptor.ts) +- [http/index.ts](file://datavines-ui/src/http/index.ts) + +**Section sources** +- [Editor/http/response.interceptor.ts](file://datavines-ui/Editor/http/response.interceptor.ts) +- [http/index.ts](file://datavines-ui/src/http/index.ts) +- [locale/zh_CN.ts](file://datavines-ui/src/locale/zh_CN.ts) +- [locale/en_US.ts](file://datavines-ui/src/locale/en_US.ts) +- [src/preset.ts](file://datavines-ui/src/preset.ts) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227.md" new file mode 100644 index 00000000..91d9bc8d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227.md" @@ -0,0 +1,421 @@ +# 开发与部署指南 + + +**本文档中引用的文件** +- [package.json](file://datavines-ui/package.json) +- [babel.config.js](file://datavines-ui/babel.config.js) +- [.eslintrc.js](file://datavines-ui/.eslintrc.js) +- [tsconfig.json](file://datavines-ui/tsconfig.json) +- [webpack.common.js](file://datavines-ui/build/webpack.common.js) +- [webpack.development.js](file://datavines-ui/build/webpack.development.js) +- [webpack.production.js](file://datavines-ui/build/webpack.production.js) +- [build.js](file://datavines-ui/build.js) +- [index-dev.html](file://datavines-ui/public/index-dev.html) +- [index-prod.html](file://datavines-ui/public/index-prod.html) +- [Dockerfile](file://deploy/docker/Dockerfile) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [.env](file://deploy/compose/.env) +- [datavines.yaml](file://deploy/k8s/datavines.yaml) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [开发环境搭建](#开发环境搭建) +4. [本地开发服务器配置](#本地开发服务器配置) +5. [代码规范与ESLint配置](#代码规范与eslint配置) +6. [构建流程与Webpack配置](#构建流程与webpack配置) +7. [生产环境构建配置](#生产环境构建配置) +8. [资源优化策略](#资源优化策略) +9. [部署方案](#部署方案) +10. [环境变量管理与多环境配置](#环境变量管理与多环境配置) +11. [常见构建错误解决方案](#常见构建错误解决方案) +12. [附录](#附录) + +## 简介 +本指南详细介绍了DataVines前端项目的完整开发与部署流程。内容涵盖开发环境搭建、本地开发服务器配置、代码规范、构建流程、生产环境优化、部署方案以及环境变量管理等关键方面。通过本指南,开发者可以快速搭建开发环境,理解项目构建机制,并成功部署应用到生产环境。 + +## 项目结构 +DataVines项目的前端代码位于`datavines-ui`目录中,采用现代化的React+TypeScript技术栈。项目结构清晰,包含源代码、构建配置、静态资源和部署文件。 + +```mermaid +graph TD +A[datavines-ui] --> B[src] +A --> C[public] +A --> D[build] +A --> E[Editor] +A --> F[typings] +A --> G[package.json] +A --> H[tsconfig.json] +A --> I[.eslintrc.js] +A --> J[webpack.config.js] +B --> B1[App] +B --> B2[action] +B --> B3[component] +B --> B4[store] +B --> B5[view] +B --> B6[utils] +B --> B7[router] +C --> C1[index-dev.html] +C --> C2[index-prod.html] +D --> D1[webpack.common.js] +D --> D2[webpack.development.js] +D --> D3[webpack.production.js] +D --> D4[utils.js] +``` + +**Diagram sources** +- [package.json](file://datavines-ui/package.json) +- [tsconfig.json](file://datavines-ui/tsconfig.json) + +**Section sources** +- [package.json](file://datavines-ui/package.json) +- [project_structure](file://project_structure) + +## 开发环境搭建 +### Node.js版本要求 +根据`package.json`文件中的依赖项,建议使用Node.js 14.x或更高版本。项目依赖的npm版本为8.19.2。 + +### 依赖安装 +通过npm安装项目依赖: +```bash +cd datavines-ui +npm install +``` + +项目主要依赖包括: +- React 18.2.0 +- Ant Design 5.0.5 +- TypeScript 4.6.4 +- Webpack 5.42.0 +- Axios 0.21.1 + +**Section sources** +- [package.json](file://datavines-ui/package.json) + +## 本地开发服务器配置 +### 开发服务器启动 +项目提供了两种开发环境配置:测试环境和生产环境。通过以下命令启动: + +```bash +# 启动测试环境开发服务器 +npm run dev:test + +# 启动生产环境开发服务器 +npm run dev:prod +``` + +### Webpack开发服务器配置 +开发服务器配置在`build/webpack.development.js`中,主要配置如下: +- 开发模式:`development` +- 端口:5000 +- 热重载:启用 +- 代理配置:将`/api`请求代理到后端服务 +- 源码映射:`cheap-module-source-map` + +代理配置允许前端开发服务器将API请求转发到后端服务,解决跨域问题。代理目标通过环境变量`DV_ENV`确定,支持`test`和`prod`环境。 + +**Section sources** +- [package.json](file://datavines-ui/package.json#L8-L9) +- [webpack.development.js](file://datavines-ui/build/webpack.development.js) + +## 代码规范与ESLint配置 +### ESLint配置 +项目使用ESLint进行代码质量检查,配置文件为`.eslintrc.js`,主要规则包括: +- 代码风格:基于Airbnb规范 +- 缩进:4个空格 +- 引号:单引号 +- 行长度:最大200字符 +- TypeScript支持:启用 +- React支持:启用 + +### 关键代码规范 +- 使用4个空格进行缩进 +- 使用单引号包裹字符串 +- JSX文件扩展名为`.tsx` +- 禁用`console`语句(开发环境除外) +- 允许未使用的变量(由TypeScript处理) + +### Babel配置 +Babel配置文件`babel.config.js`定义了代码转换规则: +- 支持ES6+语法 +- 支持React JSX +- 支持TypeScript +- 开发环境启用React热重载 +- 按需加载Ant Design组件 + +**Section sources** +- [.eslintrc.js](file://datavines-ui/.eslintrc.js) +- [babel.config.js](file://datavines-ui/babel.config.js) + +## 构建流程与Webpack配置 +### 构建脚本 +项目构建通过Webpack完成,构建脚本定义在`package.json`中: +```bash +# 构建测试环境 +npm run build:test + +# 构建生产环境 +npm run build:prod +``` + +### Webpack配置架构 +项目采用模块化的Webpack配置,包含三个主要配置文件: +- `webpack.common.js`:通用配置 +- `webpack.development.js`:开发环境配置 +- `webpack.production.js`:生产环境配置 + +配置通过`webpack-merge`工具合并。 + +### 核心构建规则 +```mermaid +flowchart TD +A[入口文件] --> B[模块解析] +B --> C[TypeScript文件] +B --> D[JavaScript文件] +B --> E[CSS文件] +B --> F[LESS文件] +B --> G[静态资源] +C --> H[babel-loader + ts-loader] +D --> I[babel-loader] +E --> J[css-loader + postcss-loader] +F --> K[less-loader + css-loader + postcss-loader] +G --> L[url-loader/file-loader] +H --> M[输出] +I --> M +J --> M +K --> M +L --> M +``` + +**Diagram sources** +- [webpack.common.js](file://datavines-ui/build/webpack.common.js) + +**Section sources** +- [webpack.common.js](file://datavines-ui/build/webpack.common.js) +- [package.json](file://datavines-ui/package.json#L10-L11) + +## 生产环境构建配置 +### 生产环境优化 +生产环境构建配置在`webpack.production.js`中,包含以下优化: +- 模式:`production` +- 代码压缩:启用TerserPlugin +- 性能提示:禁用 +- 输出路径:相对路径`./` + +### 代码压缩配置 +TerserPlugin配置了详细的压缩选项: +- 移除注释 +- 压缩代码 +- 并行处理 +- 在生产环境中移除`console`语句 + +### 输出配置 +生产环境构建输出到`dist`目录,文件结构如下: +- `js/`:JavaScript文件 +- `css/`:CSS样式文件 +- `images/`:图片资源 +- `monaco-editor/`:代码编辑器资源 +- `static/`:第三方库 + +**Section sources** +- [webpack.production.js](file://datavines-ui/build/webpack.production.js) + +## 资源优化策略 +### 代码分割 +通过Webpack的`splitChunks`功能实现代码分割: +- 将node_modules中的依赖打包到`vendors`块 +- 重复使用的代码块单独打包 +- 按需加载组件 + +### 静态资源处理 +- 图片资源:小于10KB的图片转为Base64编码,减少HTTP请求 +- 字体文件:使用file-loader处理 +- LESS/CSS:提取到单独的CSS文件 +- 第三方库:通过CopyPlugin复制到输出目录 + +### 缓存策略 +- 使用内容哈希(content hash)命名文件,实现长期缓存 +- 主文件使用`[fullhash]`,代码块使用`[chunkhash]` +- 支持浏览器缓存优化 + +**Section sources** +- [webpack.common.js](file://datavines-ui/build/webpack.common.js#L108-L128) + +## 部署方案 +### Docker部署 +项目提供Docker部署方案,相关文件位于`deploy/docker/`目录。 + +#### Dockerfile分析 +```dockerfile +FROM openjdk:8 +WORKDIR /opt +COPY datavines-dist/target/datavines-${VERSION}-bin.tar.gz . +RUN tar -zxvf datavines-${VERSION}-bin.tar.gz && \ + mv datavines-${VERSION}-bin datavines && \ + rm -rf datavines-${VERSION}-bin.tar.gz +EXPOSE 5600 +CMD ["/usr/bin/tini", "--", "datavines/bin/datavines-daemon.sh", "start_container", ""] +``` + +#### Docker Compose配置 +```yaml +version: '3.8' +services: + datavines: + image: datavines:dev + container_name: datavines + ports: + - 5600:5600 + env_file: .env + privileged: true + restart: unless-stopped +``` + +### Kubernetes部署 +Kubernetes部署配置在`deploy/k8s/datavines.yaml`中,包含: +- Deployment:定义应用部署 +- Service:定义服务暴露 +- Ingress:定义外部访问 + +#### Kubernetes资源配置 +- 命名空间:bigdata +- 副本数:1 +- 端口:5600 +- 环境变量:数据库连接信息 +- 镜像:registry.cn-shanghai.aliyuncs.com/luckydata/datavines:dev + +### Nginx部署建议 +虽然项目未提供Nginx配置,但推荐的Nginx配置如下: +```nginx +server { + listen 80; + server_name datavines.example.com; + + root /path/to/datavines/dist; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + location /api { + proxy_pass http://backend-server:5600; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + # 静态资源缓存 + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +} +``` + +**Section sources** +- [Dockerfile](file://deploy/docker/Dockerfile) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [datavines.yaml](file://deploy/k8s/datavines.yaml) + +## 环境变量管理与多环境配置 +### 环境变量配置 +项目通过环境变量实现多环境配置,主要环境变量包括: +- `DV_ENV`:前端环境(test/prod) +- `NODE_ENV`:Node.js环境(development/production) +- `SPRING_PROFILES_ACTIVE`:后端Spring配置文件 +- `SPRING_DATASOURCE_URL`:数据库连接URL +- `SPRING_DATASOURCE_USERNAME`:数据库用户名 +- `SPRING_DATASOURCE_PASSWORD`:数据库密码 + +### 多环境配置实现 +#### 前端环境配置 +通过Webpack的`DefinePlugin`将环境变量注入到代码中: +```javascript +new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), + 'process.env.DV_ENV': JSON.stringify(process.env.DV_ENV), +}) +``` + +#### 后端环境配置 +通过`.env`文件配置后端服务环境变量: +```env +SPRING_PROFILES_ACTIVE=mysql +SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/datavines?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8 +SPRING_DATASOURCE_USERNAME=root +SPRING_DATASOURCE_PASSWORD=123456 +``` + +### 环境切换流程 +1. 设置`DV_ENV`环境变量为`test`或`prod` +2. 运行相应的构建命令 +3. 启动服务或部署到目标环境 + +**Section sources** +- [webpack.common.js](file://datavines-ui/build/webpack.common.js#L173-L176) +- [.env](file://deploy/compose/.env) + +## 常见构建错误解决方案 +### TypeScript类型错误 +**问题**:TypeScript类型检查失败 +**解决方案**: +- 检查`tsconfig.json`配置 +- 确保类型定义文件正确 +- 在开发环境中使用`transpileOnly: true`跳过类型检查 + +### Webpack构建性能问题 +**问题**:构建速度慢 +**解决方案**: +- 启用`cacheDirectory`选项 +- 使用`fork-ts-checker-webpack-plugin`将类型检查放到单独进程 +- 优化`splitChunks`配置 + +### 样式加载问题 +**问题**:LESS样式未正确加载 +**解决方案**: +- 检查`less-loader`配置 +- 确保`javascriptEnabled: true` +- 验证Ant Design主题变量配置 + +### 环境变量未生效 +**问题**:环境变量未正确注入 +**解决方案**: +- 检查`DefinePlugin`配置 +- 确保环境变量在构建时设置 +- 验证`process.env`访问方式 + +### 生产环境白屏 +**问题**:生产环境部署后页面空白 +**解决方案**: +- 检查`publicPath`配置是否正确 +- 验证HTML模板路径 +- 确保静态资源路径正确 + +**Section sources** +- [webpack.common.js](file://datavines-ui/build/webpack.common.js) +- [webpack.production.js](file://datavines-ui/build/webpack.production.js) + +## 附录 +### 构建流程图 +```mermaid +flowchart TD +A[源代码] --> B[开发环境] +A --> C[生产环境] +B --> D[webpack serve] +D --> E[热重载] +D --> F[源码映射] +D --> G[代理API] +C --> H[webpack 构建] +H --> I[代码压缩] +H --> J[代码分割] +H --> K[资源优化] +H --> L[输出dist目录] +L --> M[Docker部署] +L --> N[Kubernetes部署] +L --> O[Nginx部署] +``` + +**Diagram sources** +- [webpack.development.js](file://datavines-ui/build/webpack.development.js) +- [webpack.production.js](file://datavines-ui/build/webpack.production.js) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227/\345\274\200\345\217\221\347\216\257\345\242\203\346\220\255\345\273\272.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227/\345\274\200\345\217\221\347\216\257\345\242\203\346\220\255\345\273\272.md" new file mode 100644 index 00000000..8f352ed5 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227/\345\274\200\345\217\221\347\216\257\345\242\203\346\220\255\345\273\272.md" @@ -0,0 +1,306 @@ +# 开发环境搭建 + + +**本文档中引用的文件** +- [package.json](file://datavines-ui/package.json) +- [.eslintrc.js](file://datavines-ui/.eslintrc.js) +- [.editorconfig](file://datavines-ui/.editorconfig) +- [tsconfig.json](file://datavines-ui/tsconfig.json) +- [webpack.common.js](file://datavines-ui/build/webpack.common.js) +- [webpack.development.js](file://datavines-ui/build/webpack.development.js) +- [webpack.production.js](file://datavines-ui/build/webpack.production.js) +- [babel.config.js](file://datavines-ui/babel.config.js) +- [postcss.config.js](file://datavines-ui/postcss.config.js) +- [index-dev.html](file://datavines-ui/public/index-dev.html) +- [index-prod.html](file://datavines-ui/public/index-prod.html) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [Node.js与npm版本要求](#nodejs与npm版本要求) +4. [依赖安装](#依赖安装) +5. [代码规范配置](#代码规范配置) +6. [IDE配置](#ide配置) +7. [本地开发服务器](#本地开发服务器) +8. [热重载功能](#热重载功能) +9. [调试技巧](#调试技巧) +10. [常见问题解决方案](#常见问题解决方案) + +## 简介 +本指南详细说明如何为DataVines前端项目搭建开发环境。涵盖Node.js和npm的版本要求、依赖安装、代码规范配置(ESLint、EditorConfig)、主流IDE配置、本地开发服务器启动方法、热重载功能和调试技巧,以及开发环境中常见问题的解决方案。 + +## 项目结构 +DataVines项目的前端代码位于`datavines-ui`目录下,采用React + TypeScript技术栈,使用Webpack进行构建。项目结构清晰,包含组件、页面、工具函数、状态管理等模块。 + +```mermaid +graph TD +A[datavines-ui] --> B[public] +A --> C[src] +A --> D[Editor] +A --> E[build] +A --> F[typings] +B --> G[index-dev.html] +B --> H[index-prod.html] +C --> I[App] +C --> J[component] +C --> K[view] +C --> L[store] +C --> M[utils] +E --> N[webpack.common.js] +E --> O[webpack.development.js] +E --> P[webpack.production.js] +``` + +**Diagram sources** +- [public/index-dev.html](file://datavines-ui/public/index-dev.html) +- [public/index-prod.html](file://datavines-ui/public/index-prod.html) +- [build/webpack.common.js](file://datavines-ui/build/webpack.common.js) +- [build/webpack.development.js](file://datavines-ui/build/webpack.development.js) +- [build/webpack.production.js](file://datavines-ui/build/webpack.production.js) + +**Section sources** +- [package.json](file://datavines-ui/package.json) + +## Node.js与npm版本要求 +根据`package.json`文件中的依赖项,建议使用以下版本: +- **Node.js**: 推荐使用LTS版本(如16.x或18.x),以确保与所有依赖包兼容 +- **npm**: 建议使用Node.js自带的npm版本(通常为8.x或更高版本) + +项目中明确指定了`npm`版本为`^8.19.2`,建议保持此版本范围以避免潜在的构建问题。 + +**Section sources** +- [package.json](file://datavines-ui/package.json#L31) + +## 依赖安装 +使用npm安装项目依赖: + +```bash +cd datavines/datavines-ui +npm install +``` + +或者使用yarn(如果已安装): + +```bash +yarn install +``` + +安装完成后,您将拥有所有必要的开发和生产依赖,包括React、Ant Design、TypeScript、Webpack等。 + +**Section sources** +- [package.json](file://datavines-ui/package.json) + +## 代码规范配置 +### ESLint配置 +项目使用ESLint进行代码质量检查,配置文件为`.eslintrc.js`。主要规则包括: +- 使用4个空格进行缩进 +- 使用单引号 +- 最大行长度为200字符 +- 启用TypeScript支持 +- 基于Airbnb风格指南 + +```javascript +module.exports = { + env: { + browser: true, + node: true, + es2021: true, + }, + extends: [ + 'airbnb', + 'plugin:import/typescript', + ], + parser: '@typescript-eslint/parser', + rules: { + indent: ['error', 4], + quotes: ['error', 'single'], + 'max-len': ['error', { code: 200 }], + // ...其他规则 + }, +}; +``` + +### EditorConfig配置 +项目使用`.editorconfig`文件统一编辑器配置: +- 字符编码:UTF-8 +- 换行符:LF +- 缩进风格:空格 +- 缩进大小:4个空格 +- 删除行尾空白字符 + +```ini +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +``` + +### TypeScript配置 +`tsconfig.json`文件定义了TypeScript编译选项: +- 支持路径别名(@、@Editor等) +- 严格类型检查 +- ESNext目标 +- 包含源文件和类型声明文件 + +**Section sources** +- [.eslintrc.js](file://datavines-ui/.eslintrc.js) +- [.editorconfig](file://datavines-ui/.editorconfig) +- [tsconfig.json](file://datavines-ui/tsconfig.json) + +## IDE配置 +### VS Code配置 +在VS Code中,确保安装以下扩展: +- ESLint +- Prettier - Code formatter +- TypeScript Hero +- Path Intellisense + +项目会自动应用ESLint和EditorConfig规则。您可以在VS Code设置中启用"Format on Save"以自动格式化代码。 + +### WebStorm配置 +在WebStorm中: +1. 启用ESLint:Settings → Languages & Frameworks → JavaScript → Code Quality Tools → ESLint +2. 启用EditorConfig支持 +3. 配置TypeScript:Settings → Languages & Frameworks → TypeScript +4. 设置代码格式化为4个空格缩进 + +### 其他IDE +对于其他IDE,确保支持: +- ESLint集成 +- EditorConfig插件 +- TypeScript语言服务 +- 路径别名解析(@ → src, @Editor → Editor) + +**Section sources** +- [.eslintrc.js](file://datavines-ui/.eslintrc.js) +- [.editorconfig](file://datavines-ui/.editorconfig) +- [tsconfig.json](file://datavines-ui/tsconfig.json) + +## 本地开发服务器 +项目提供两种开发服务器配置,通过不同的环境变量启动: + +### 启动测试环境开发服务器 +```bash +npm run dev:test +``` + +### 启动生产环境开发服务器 +```bash +npm run dev:prod +``` + +开发服务器使用Webpack Dev Server,运行在端口5000上,支持热重载和代理API请求。 + +```mermaid +sequenceDiagram +participant Browser as 浏览器 +participant DevServer as Webpack Dev Server +participant Backend as 后端服务 +Browser->>DevServer : 访问 http : //localhost : 5000 +DevServer-->>Browser : 返回开发版HTML +Browser->>DevServer : 请求JS/CSS资源 +DevServer-->>Browser : 返回编译后的资源 +Browser->>DevServer : API请求 (/api/*) +DevServer->>Backend : 代理到目标服务器 +Backend-->>DevServer : 返回API响应 +DevServer-->>Browser : 返回API响应 +``` + +**Diagram sources** +- [webpack.development.js](file://datavines-ui/build/webpack.development.js) +- [package.json](file://datavines-ui/package.json#L8-L9) + +**Section sources** +- [webpack.development.js](file://datavines-ui/build/webpack.development.js) +- [package.json](file://datavines-ui/package.json) + +## 热重载功能 +开发服务器支持模块热替换(HMR),当您修改代码时: +1. Webpack检测文件变化 +2. 重新编译修改的模块 +3. React Refresh插件更新组件状态 +4. 浏览器无需刷新即可看到更改 + +热重载配置在`webpack.development.js`中: +- `hot: true` 启用热模块替换 +- `ReactRefreshWebpackPlugin` 处理React组件热更新 +- `webpack.HotModuleReplacementPlugin` 核心HMR插件 + +这确保了快速的开发反馈循环,同时保持应用状态。 + +**Section sources** +- [webpack.development.js](file://datavines-ui/build/webpack.development.js#L51) +- [babel.config.js](file://datavines-ui/babel.config.js#L9) + +## 调试技巧 +### 浏览器调试 +1. 使用Chrome开发者工具 +2. 启用Source Maps(已在开发配置中启用) +3. 在源代码中设置断点 +4. 使用React DevTools检查组件树 + +### IDE调试 +在VS Code中配置调试: +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Dev Server", + "type": "chrome", + "request": "launch", + "url": "http://localhost:5000", + "webRoot": "${workspaceFolder}/datavines-ui", + "sourceMapPathOverrides": { + "webpack:///./src/*": "${webRoot}/src/*" + } + } + ] +} +``` + +### 网络请求调试 +开发服务器配置了API代理,所有`/api`请求将被代理到后端服务。您可以在`build/.proxy.example.js`中配置代理目标。 + +**Section sources** +- [webpack.development.js](file://datavines-ui/build/webpack.development.js#L54-L62) +- [build/.proxy.example.js](file://datavines-ui/build/.proxy.example.js) + +## 常见问题解决方案 +### 依赖冲突 +如果遇到依赖冲突,尝试: +1. 删除`node_modules`和`package-lock.json` +2. 重新运行`npm install` +3. 使用`npm ls `检查依赖树 + +### 端口占用 +如果端口5000被占用: +1. 修改`webpack.development.js`中的`port`配置 +2. 或使用`npm run dev:test -- --port 5001`指定端口 + +### 构建错误 +常见构建错误及解决方案: +- **TypeScript类型错误**:检查`tsconfig.json`配置和类型定义 +- **模块解析错误**:确保路径别名正确配置 +- **样式加载错误**:检查`webpack.common.js`中的less/css规则 + +### 热重载失效 +如果热重载不工作: +1. 检查控制台是否有错误 +2. 确保`ReactRefreshWebpackPlugin`已正确配置 +3. 重启开发服务器 + +### 环境变量问题 +确保正确设置环境变量: +- `DV_ENV=test` 或 `DV_ENV=prod` +- 可在`.env`文件中设置 + +**Section sources** +- [webpack.development.js](file://datavines-ui/build/webpack.development.js#L49) +- [webpack.common.js](file://datavines-ui/build/webpack.common.js) +- [package.json](file://datavines-ui/package.json) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227/\347\224\237\344\272\247\347\216\257\345\242\203\351\203\250\347\275\262.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227/\347\224\237\344\272\247\347\216\257\345\242\203\351\203\250\347\275\262.md" new file mode 100644 index 00000000..c0f0d1b8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\345\274\200\345\217\221\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227/\347\224\237\344\272\247\347\216\257\345\242\203\351\203\250\347\275\262.md" @@ -0,0 +1,262 @@ +# 生产环境部署 + + +**本文档引用的文件** +- [Dockerfile](file://deploy/docker/Dockerfile) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [datavines.yaml](file://deploy/k8s/datavines.yaml) +- [.env](file://deploy/compose/.env) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml) +- [webpack.production.js](file://datavines-ui/build/webpack.production.js) +- [webpack.common.js](file://datavines-ui/build/webpack.common.js) +- [index-prod.html](file://datavines-ui/public/index-prod.html) +- [package.json](file://datavines-ui/package.json) + + +## 目录 +1. [引言](#引言) +2. [生产构建配置与优化策略](#生产构建配置与优化策略) +3. [Docker镜像构建流程](#docker镜像构建流程) +4. [Nginx反向代理与静态资源服务](#nginx反向代理与静态资源服务) +5. [多环境变量管理](#多环境变量管理) +6. [部署验证与回滚方案](#部署验证与回滚方案) + +## 引言 +本文档旨在为DataVines大数据平台提供完整的生产环境部署指南。文档详细说明了从代码构建、Docker镜像创建到Kubernetes部署的完整流程,涵盖了生产环境部署的关键方面,包括构建优化、容器化部署、反向代理配置和多环境管理策略。 + +## 生产构建配置与优化策略 + +### 代码压缩与资源哈希 +DataVines前端应用使用Webpack进行构建,生产环境配置了代码压缩和资源哈希功能,以优化性能和缓存策略。 + +在`webpack.production.js`中,配置了TerserPlugin进行JavaScript代码压缩,移除注释和console.log语句,减小文件体积: + +```mermaid +flowchart TD +A[源代码] --> B[Webpack构建] +B --> C[TerserPlugin代码压缩] +C --> D[生成哈希文件名] +D --> E[输出优化后的静态资源] +``` + +**Diagram sources** +- [webpack.production.js](file://datavines-ui/build/webpack.production.js#L1-L47) + +**Section sources** +- [webpack.production.js](file://datavines-ui/build/webpack.production.js#L1-L47) +- [webpack.common.js](file://datavines-ui/build/webpack.common.js#L1-L179) + +### 懒加载配置 +通过Webpack的代码分割功能实现组件的懒加载,提高应用的初始加载性能。在`webpack.common.js`中配置了splitChunks,将第三方库和应用代码分离: + +```mermaid +flowchart LR +A[应用入口] --> B[主包] +A --> C[第三方库包] +A --> D[组件包] +B --> E[按需加载] +C --> E +D --> E +``` + +**Diagram sources** +- [webpack.common.js](file://datavines-ui/build/webpack.common.js#L108-L128) + +### 构建命令 +前端应用提供了不同的构建命令,支持测试和生产环境的构建: + +```json +{ + "scripts": { + "build:test": "rimraf dist && webpack --env DV_ENV=test", + "build:prod": "rimraf dist && webpack --env DV_ENV=prod" + } +} +``` + +**Section sources** +- [package.json](file://datavines-ui/package.json#L1-L100) + +## Docker镜像构建流程 + +### Dockerfile配置 +DataVines提供了完整的Dockerfile用于创建生产环境镜像。Dockerfile基于OpenJDK 8基础镜像,安装了必要的系统工具,并复制了构建好的应用程序包。 + +```dockerfile +FROM openjdk:8 + +MAINTAINER 735140144 + +ARG VERSION=1.0.0-SNAPSHOT + +ENV TZ=Asia/Shanghai +ENV LANG=zh_CN.UTF-8 + +WORKDIR /opt + +RUN apt-get update && \ + apt-get install -y tini && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +COPY datavines-dist/target/datavines-${VERSION}-bin.tar.gz . +``` + +**Section sources** +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) + +### 构建命令 +Docker镜像的构建流程包括Maven打包和Docker构建两个步骤: + +1. 使用Maven打包应用程序: +```bash +mvn clean package -Pdocker -DskipTests +``` + +2. 构建Docker镜像: +```bash +docker build -t datavines:dev -f deploy/docker/Dockerfile . +``` + +## Nginx反向代理配置和静态资源服务 + +### 静态资源优化 +DataVines前端应用的生产构建配置了静态资源的优化策略,包括文件哈希和CDN友好的路径配置: + +```javascript +output: { + publicPath: './', + path: resolve('dist'), + filename: 'js/[name].[fullhash:8].js', + chunkFilename: 'js/[name].[chunkhash:8].js', +} +``` + +**Section sources** +- [webpack.production.js](file://datavines-ui/build/webpack.production.js#L12-L18) + +### 反向代理配置 +虽然项目中没有直接提供Nginx配置文件,但通过Kubernetes Ingress和Docker Compose配置可以推断出反向代理的需求。建议的Nginx配置如下: + +```nginx +server { + listen 80; + server_name datavines.example.com; + + location / { + root /usr/share/nginx/html; + try_files $uri $uri/ /index.html; + expires 1y; + add_header Cache-Control "public, immutable"; + } + + location /api/ { + proxy_pass http://datavines-server:5600; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} +``` + +## 多环境变量管理 + +### 环境配置文件 +DataVines使用Spring Profiles管理多环境配置,通过`.env`文件设置环境变量: + +```env +SPRING_PROFILES_ACTIVE=mysql +SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/datavines?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8 +SPRING_DATASOURCE_USERNAME=root +SPRING_DATASOURCE_PASSWORD=123456 +SPRING_DATASOURCE_DRIVER-CLASS_NAME=com.mysql.cj.jdbc.Driver +``` + +**Section sources** +- [.env](file://deploy/compose/.env#L1-L5) + +### 多数据源配置 +在`application.yaml`中配置了MySQL和PostgreSQL两种数据库的支持,通过Spring Profiles切换: + +```yaml +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://127.0.0.1:5432/datavines + username: postgres + password: 123456 +--- +spring: + config: + activate: + on-profile: mysql + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/datavines?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai +``` + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) + +## 部署验证和回滚方案 + +### Docker Compose部署 +使用Docker Compose进行本地或测试环境部署,配置了容器的网络、端口映射和重启策略: + +```yaml +version: '3.8' +services: + datavines: + image: datavines:dev + container_name: datavines + ports: + - 5600:5600 + env_file: .env + privileged: true + restart: unless-stopped + networks: + - datavines + +networks: + datavines: + driver: bridge + ipam: + config: + - subnet: 172.18.0.0/24 +``` + +**Section sources** +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) + +### Kubernetes部署 +生产环境推荐使用Kubernetes进行部署,提供了完整的Deployment、Service和Ingress配置: + +```mermaid +graph TD +A[用户请求] --> B[Ingress] +B --> C[Service] +C --> D[Datavines Pod] +D --> E[数据库] +``` + +**Diagram sources** +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L112) + +### 回滚方案 +Kubernetes配置了滚动更新策略,支持安全的版本回滚: + +```yaml +strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate +``` + +通过以下命令可以执行回滚: +```bash +kubectl rollout undo deployment/datavines +``` + +**Section sources** +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L112) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\344\273\273\345\212\241\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\344\273\273\345\212\241\347\256\241\347\220\206.md" new file mode 100644 index 00000000..1db49137 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\344\273\273\345\212\241\347\256\241\347\220\206.md" @@ -0,0 +1,277 @@ +# 任务管理 + + +**本文档引用的文件** +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) +- [useAddEditJobsModal/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useAddEditJobsModal\index.tsx) +- [components/Schedule/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\components\Schedule\index.tsx) +- [useLogger/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useLogger\index.tsx) +- [Jobs.ts](file://datavines-ui\src\type\Jobs.ts) +- [JobsInstance.ts](file://datavines-ui\src\type\JobsInstance.ts) +- [zh_CN.ts](file://datavines-ui\src\locale\zh_CN.ts) +- [detailRouter.tsx](file://datavines-ui\src\router\detailRouter.tsx) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录)(如有必要) + +## 简介 +本文档详细描述了datavines-ui中的任务管理功能,涵盖任务列表页面和任务实例详情页面的布局结构与功能模块。文档解释了任务创建、编辑、执行监控和日志查看的完整流程,说明了任务调度配置、执行参数设置和结果展示的用户交互设计,并提供了任务管理组件的开发实现细节和性能优化建议。 + +## 项目结构 +datavines-ui的任务管理功能主要位于`src/view/Main/HomeDetail/Jobs`目录下,包含任务列表、任务实例、任务创建与编辑、调度配置、日志查看等核心组件。该功能通过React路由与主应用集成,支持数据质量作业和数据比对作业的管理。 + +```mermaid +graph TB +subgraph "任务管理模块" +JobsList[任务列表页面] +JobsInstance[任务实例详情页面] +AddEditModal[任务创建与编辑模态框] +ScheduleConfig[调度配置组件] +Logger[日志查看组件] +end +JobsList --> JobsInstance +JobsList --> AddEditModal +AddEditModal --> ScheduleConfig +JobsInstance --> Logger +``` + +**图示来源** +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) +- [useAddEditJobsModal/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useAddEditJobsModal\index.tsx) +- [components/Schedule/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\components\Schedule\index.tsx) +- [useLogger/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useLogger\index.tsx) + +**章节来源** +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) + +## 核心组件 +任务管理功能的核心组件包括任务列表页面(JobsList.tsx)、任务实例详情页面(JobsInstance.tsx)、任务创建与编辑模态框(useAddEditJobsModal)、调度配置组件(Schedule)和日志查看组件(useLogger)。这些组件通过React Hooks和Ant Design组件库实现用户交互和状态管理。 + +**章节来源** +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) +- [useAddEditJobsModal/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useAddEditJobsModal\index.tsx) + +## 架构概述 +任务管理功能采用基于React的组件化架构,通过Redux管理全局状态,使用Ant Design作为UI组件库。前端通过HTTP API与后端服务通信,实现任务的CRUD操作、执行控制和日志查询。路由系统将任务管理功能集成到主应用中,支持多标签页导航。 + +```mermaid +graph LR +A[前端UI] --> B[HTTP API] +B --> C[后端服务] +C --> D[数据库] +A --> E[Redux状态管理] +E --> A +F[路由系统] --> A +``` + +**图示来源** +- [detailRouter.tsx](file://datavines-ui\src\router\detailRouter.tsx) +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) + +## 详细组件分析 + +### 任务列表页面分析 +任务列表页面(JobsList.tsx)展示所有任务的概览信息,支持搜索、分页、运行、编辑、删除、预览和查看实例等操作。页面通过Tabs组件区分数据质量作业和数据比对作业,使用Table组件展示任务列表。 + +#### 组件结构 +```mermaid +classDiagram +class JobsList { ++useState() ++useForm() ++useIntl() ++useHistory() ++useRouteMatch() ++getData() ++onSearch() ++onChange() ++onRun() ++onEdit() ++onDelete() ++onSLAs() ++onViewInstance() ++onPreviewInstance() +} +JobsList --> Table : "使用" +JobsList --> Form : "使用" +JobsList --> Button : "使用" +JobsList --> Dropdown : "使用" +JobsList --> Menu : "使用" +JobsList --> Tabs : "使用" +JobsList --> DatePicker : "使用" +JobsList --> useAddEditJobsModal : "使用" +JobsList --> useSelectSLAsModal : "使用" +JobsList --> useJobExecutionConfigPreview : "使用" +``` + +**图示来源** +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) + +**章节来源** +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) + +### 任务实例详情页面分析 +任务实例详情页面(JobsInstance.tsx)展示特定任务的所有执行实例,支持查看日志、结果和错误数据。页面通过Table组件展示实例列表,使用模态框组件查看详细信息。 + +#### 组件结构 +```mermaid +classDiagram +class JobsInstance { ++useState() ++useForm() ++useIntl() ++useWatch() ++getData() ++onSearch() ++onChange() ++onStop() ++onLog() ++onResult() ++onErrorData() +} +JobsInstance --> Table : "使用" +JobsInstance --> Form : "使用" +JobsInstance --> SearchForm : "使用" +JobsInstance --> useLogger : "使用" +JobsInstance --> useInstanceErrorDataModal : "使用" +JobsInstance --> useInstanceResult : "使用" +``` + +**图示来源** +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) + +**章节来源** +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) + +### 任务创建与编辑分析 +任务创建与编辑功能通过模态框组件(useAddEditJobsModal)实现,支持多标签页配置,包括作业配置、定时任务配置、SLA配置和配置文件。用户可以保存、保存并运行或保存并预览任务。 + +#### 用户交互流程 +```mermaid +flowchart TD +Start([打开创建/编辑模态框]) --> Tabs["选择配置标签页"] +Tabs --> |作业配置| JobConfig["配置作业参数"] +Tabs --> |定时任务配置| ScheduleConfig["配置调度参数"] +Tabs --> |SLA配置| SLAConfig["配置SLA参数"] +Tabs --> |配置文件| ConfigFile["查看/复制/下载配置文件"] +JobConfig --> Save["选择保存方式"] +ScheduleConfig --> Save +SLAConfig --> Save +ConfigFile --> Save +Save --> |保存| SaveAction["调用API保存任务"] +Save --> |保存并运行| SaveRunAction["调用API保存并运行任务"] +Save --> |保存并预览| SavePreviewAction["调用API保存并预览任务"] +SaveAction --> End([关闭模态框]) +SaveRunAction --> End +SavePreviewAction --> End +``` + +**图示来源** +- [useAddEditJobsModal/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useAddEditJobsModal\index.tsx) + +**章节来源** +- [useAddEditJobsModal/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useAddEditJobsModal\index.tsx) + +### 调度配置分析 +调度配置组件(Schedule)支持三种调度类型:常规调度、Crontab调度和不调度。常规调度提供月、周、日、小时、每N小时、每N分钟等周期选项,Crontab调度支持自定义表达式和未来执行计划查看。 + +#### 配置选项 +| 调度类型 | 配置选项 | 说明 | +|---------|--------|------| +| 常规调度 | 月、周、日、小时、每N小时、每N分钟 | 提供可视化的时间选择界面 | +| Crontab调度 | 自定义表达式 | 支持标准Crontab语法 | +| 不调度 | 无 | 任务不会自动执行 | + +**图示来源** +- [components/Schedule/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\components\Schedule\index.tsx) + +**章节来源** +- [components/Schedule/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\components\Schedule\index.tsx) + +### 日志查看分析 +日志查看组件(useLogger)通过模态框展示任务执行日志,支持刷新、下载和全屏查看。日志内容按行加载,支持增量获取。 + +#### 功能特性 +- **实时刷新**:用户可手动刷新获取最新日志 +- **日志下载**:支持将日志保存为文件 +- **增量加载**:按行偏移量获取日志内容 +- **HTML渲染**:支持换行符转换为HTML标签 + +**章节来源** +- [useLogger/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useLogger\index.tsx) + +## 依赖分析 +任务管理功能依赖于多个内部和外部组件,包括UI组件库、状态管理、HTTP客户端和国际化支持。组件间通过props和回调函数进行通信,形成清晰的依赖关系。 + +```mermaid +graph TD +JobsList --> useAddEditJobsModal +JobsList --> useSelectSLAsModal +JobsList --> useJobExecutionConfigPreview +JobsInstance --> useLogger +JobsInstance --> useInstanceErrorDataModal +JobsInstance --> useInstanceResult +useAddEditJobsModal --> Schedule +useAddEditJobsModal --> SelectSLAsComponent +useAddEditJobsModal --> useJobExecutionConfigPreview +Schedule --> PageContainer +useLogger --> $http +useInstanceErrorDataModal --> $http +useInstanceResult --> $http +JobsList --> $http +JobsInstance --> $http +``` + +**图示来源** +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) +- [useAddEditJobsModal/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useAddEditJobsModal\index.tsx) +- [components/Schedule/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\components\Schedule\index.tsx) +- [useLogger/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useLogger\index.tsx) + +**章节来源** +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) + +## 性能考虑 +任务管理功能在性能方面考虑了以下优化点: +- **分页加载**:任务列表和实例列表均采用分页方式,避免一次性加载大量数据 +- **懒加载**:使用React.lazy实现组件的懒加载,减少初始加载时间 +- **状态管理**:使用Redux集中管理应用状态,避免不必要的组件重渲染 +- **API调用优化**:在用户操作后才调用API获取数据,避免频繁请求 + +## 故障排除指南 +### 常见问题 +1. **任务无法创建**:检查作业名称是否为空,确保所有必填字段已填写 +2. **调度配置不生效**:确认调度类型选择正确,检查时间范围是否合理 +3. **日志无法加载**:检查网络连接,尝试刷新页面或重新登录 +4. **实例无法停止**:确认任务处于可停止状态(已提交、执行中、待提交) + +### 调试建议 +- 使用浏览器开发者工具查看网络请求,确认API调用是否成功 +- 检查控制台是否有JavaScript错误 +- 验证用户权限是否足够执行相关操作 +- 查看后端服务日志获取更多错误信息 + +**章节来源** +- [JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [JobsInstance.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsInstance.tsx) +- [useLogger/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useLogger\index.tsx) + +## 结论 +datavines-ui的任务管理功能提供了完整的任务生命周期管理,从创建、编辑、调度到执行监控和日志查看。功能设计考虑了用户体验和性能优化,通过组件化架构实现了高内聚低耦合。建议在后续开发中进一步优化大规模数据下的分页性能,并增加更多调度策略的可视化配置选项。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\345\221\212\350\255\246\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\345\221\212\350\255\246\347\256\241\347\220\206.md" new file mode 100644 index 00000000..6f6efecd --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\345\221\212\350\255\246\347\256\241\347\220\206.md" @@ -0,0 +1,167 @@ +# 告警管理 + + +**本文档引用的文件** +- [index.tsx](file://datavines-ui\src\view\Main\Warning\index.tsx) +- [SLAsList.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\SLAsList.tsx) +- [NoticeList.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\NoticeList.tsx) +- [Notification.tsx](file://datavines-ui\src\view\Main\Warning\SLAsSetting\Notification.tsx) +- [CreateSLAs.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\hooks\CreateSLAs.tsx) +- [CreateWidget.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\hooks\CreateWidget.tsx) +- [useNotificationFormModal.tsx](file://datavines-ui\src\view\Main\Warning\SLAsSetting\useNotificationFormModal.tsx) +- [warning.ts](file://datavines-ui\src\type\warning.ts) +- [Notification.ts](file://datavines-ui\src\type\Notification.ts) + + +## 目录 +1. [简介](#简介) +2. [页面布局与功能模块](#页面布局与功能模块) +3. [SLA规则操作流程](#sla规则操作流程) +4. [告警通知记录交互设计](#告警通知记录交互设计) +5. [开发实现细节](#开发实现细节) +6. [常见问题解决方案](#常见问题解决方案) + +## 简介 +datavines-ui的告警管理功能为用户提供了一套完整的SLA(服务等级协议)配置与通知管理机制。该功能主要包含SLA配置、通知列表、告警监控等核心模块,支持用户创建、编辑、启用/禁用SLA规则,并配置相应的通知渠道。系统通过直观的用户界面和灵活的配置选项,帮助用户有效监控数据质量并及时响应异常情况。 + +## 页面布局与功能模块 + +### SLA配置页面布局 +SLA配置页面(SLAsList)采用标准的列表展示模式,主要包含以下功能区域: +- **搜索区域**:位于页面顶部,提供搜索框用于快速查找SLA规则 +- **操作按钮区**:包含"创建SLA"按钮,用于新建SLA规则 +- **数据表格区**:展示所有SLA规则的详细信息,包括名称、描述、更新人、更新时间等字段 +- **分页控件**:支持分页浏览大量SLA规则 + +页面通过Ant Design的Table组件实现数据展示,支持分页、排序等交互功能。 + +### 通知列表页面布局 +通知列表页面(NoticeList)与SLA配置页面采用相似的布局结构: +- **搜索区域**:提供搜索功能,支持按名称等条件筛选通知配置 +- **创建按钮**:包含"创建通知"按钮,用于添加新的通知渠道 +- **表格展示区**:显示所有通知配置的详细信息,包括通知名称、类型、更新人、更新时间等 +- **分页功能**:支持分页浏览通知配置列表 + +**页面来源** +- [SLAsList.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\SLAsList.tsx) +- [NoticeList.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\NoticeList.tsx) + +## SLA规则操作流程 + +### 创建SLA规则 +1. 用户点击"创建SLA"按钮 +2. 系统弹出创建SLA的模态对话框 +3. 用户填写SLA名称和描述信息 +4. 点击确认按钮,系统通过POST请求`/sla`接口创建新的SLA规则 +5. 创建成功后自动刷新SLA列表 + +### 编辑SLA规则 +1. 用户在SLA列表中点击"编辑"链接 +2. 系统弹出编辑SLA的模态对话框,预填充现有信息 +3. 用户修改SLA名称或描述 +4. 点击确认按钮,系统通过PUT请求`/sla`接口更新SLA规则 +5. 更新成功后自动刷新SLA列表 + +### 启用/禁用SLA规则 +系统通过SLA规则的状态字段来管理启用/禁用状态。当用户需要禁用某个SLA规则时,可以通过编辑操作将其状态设置为禁用。启用操作则相反,将状态设置为启用。 + +**操作流程来源** +- [CreateSLAs.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\hooks\CreateSLAs.tsx) + +## 告警通知记录交互设计 + +### 通知记录展示 +告警通知记录通过表格形式展示,包含以下字段: +- 通知名称 +- 通知类型(如邮件、钉钉等) +- 更新人 +- 更新时间 +- 操作列(包含编辑和删除操作) + +### 筛选功能 +系统提供搜索框作为筛选入口,用户可以输入关键词来筛选通知记录。筛选操作会触发API请求,将搜索条件作为参数传递给后端服务。 + +### 查看详情 +系统通过SLA设置页面(SLAsSetting)提供通知详情查看功能: +1. 用户从SLA监控页面进入设置页面 +2. 在设置页面中选择"通知"标签页 +3. 查看该SLA关联的所有通知配置 +4. 可以点击"编辑"按钮查看具体配置详情 + +**交互设计来源** +- [Notification.tsx](file://datavines-ui\src\view\Main\Warning\SLAsSetting\Notification.tsx) +- [useNotificationFormModal.tsx](file://datavines-ui\src\view\Main\Warning\SLAsSetting\useNotificationFormModal.tsx) + +## 开发实现细节 + +### 组件结构 +告警管理功能采用模块化组件设计: +- **主容器组件**:Warning/index.tsx,负责路由分发 +- **列表组件**:SLAsList和NoticeList,负责数据展示 +- **表单组件**:通过CreateSLAs和CreateWidget等钩子函数实现 +- **设置组件**:SLAsSetting,提供SLA详细配置功能 + +### 状态管理 +系统使用React的useState和useRef等Hook进行状态管理: +- 使用useState管理组件的本地状态(如加载状态、分页参数等) +- 使用useRef保存对DOM元素或组件实例的引用 +- 通过useSelector从Redux store中获取全局状态 + +### API交互 +系统通过$http服务与后端进行数据交互,主要API接口包括: +- `GET /sla/page`:获取SLA规则分页列表 +- `POST /sla`:创建SLA规则 +- `PUT /sla`:更新SLA规则 +- `DELETE /sla/{id}`:删除SLA规则 +- `GET /sla/sender/page`:获取通知配置分页列表 + +### 类型定义 +系统在type目录下定义了相关类型: +- TWarnSLATableItem:SLA规则数据类型 +- TWarnTableItem:通知配置数据类型 +- NoticeDynamicItem:动态表单配置类型 + +**实现细节来源** +- [CreateSLAs.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\hooks\CreateSLAs.tsx) +- [CreateWidget.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\hooks\CreateWidget.tsx) +- [warning.ts](file://datavines-ui\src\type\warning.ts) +- [Notification.ts](file://datavines-ui\src\type\Notification.ts) + +## 常见问题解决方案 + +### SLA创建失败 +**问题现象**:创建SLA时提示失败 +**解决方案**: +1. 检查网络连接是否正常 +2. 确认SLA名称是否已存在 +3. 验证必填字段是否完整填写 +4. 查看浏览器控制台是否有错误信息 + +### 通知配置无法保存 +**问题现象**:编辑通知配置后无法保存 +**解决方案**: +1. 检查通知类型是否选择正确 +2. 确认所有必填字段都已填写 +3. 验证配置参数是否符合要求 +4. 尝试使用"测试发送"功能验证配置正确性 + +### 数据加载缓慢 +**问题现象**:SLA或通知列表加载缓慢 +**解决方案**: +1. 减少列表中的数据量,使用分页功能 +2. 优化搜索条件,避免全表扫描 +3. 检查后端服务性能 +4. 确认网络带宽是否充足 + +### 通知发送失败 +**问题现象**:配置的通知无法正常发送 +**解决方案**: +1. 使用"测试发送"功能验证配置 +2. 检查通知渠道的认证信息是否正确 +3. 确认接收方地址是否有效 +4. 查看系统日志获取详细错误信息 + +**问题解决方案来源** +- [CreateSLAs.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\hooks\CreateSLAs.tsx) +- [CreateWidget.tsx](file://datavines-ui\src\view\Main\Warning\SLAsNoticeList\hooks\CreateWidget.tsx) +- [useNotificationFormModal.tsx](file://datavines-ui\src\view\Main\Warning\SLAsSetting\useNotificationFormModal.tsx) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275.md" new file mode 100644 index 00000000..785d6e2b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275.md" @@ -0,0 +1,190 @@ +# 核心页面功能 + + +**本文档引用的文件** +- [mainRouter.tsx](file://datavines-ui\src\router\mainRouter.tsx) +- [detailRouter.tsx](file://datavines-ui\src\router\detailRouter.tsx) +- [Home/index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx) +- [Home/List/Table.tsx](file://datavines-ui\src\view\Main\Home\List\Table.tsx) +- [Home/List/Card.tsx](file://datavines-ui\src\view\Main\Home\List\Card.tsx) +- [Home/AddDataSource/index.tsx](file://datavines-ui\src\view\Main\Home\AddDataSource\index.tsx) +- [Home/List/MetaDataFetcher.tsx](file://datavines-ui\src\view\Main\Home\List\MetaDataFetcher.tsx) +- [HomeDetail/Jobs/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\index.tsx) +- [HomeDetail/Jobs/JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [HomeDetail/Jobs/useAddEditJobsModal/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useAddEditJobsModal\index.tsx) +- [Warning/SLAsSetting/index.tsx](file://datavines-ui\src\view\Main\Warning\SLAsSetting\index.tsx) +- [Warning/SLAsSetting/Notification.tsx](file://datavines-ui\src\view\Main\Warning\SLAsSetting\Notification.tsx) +- [store/index.ts](file://datavines-ui\src\store\index.ts) + + +## 目录 +1. [首页(数据源概览)](#首页数据源概览) +2. [任务管理](#任务管理) +3. [告警管理](#告警管理) +4. [用户管理](#用户管理) +5. [页面导航与数据传递](#页面导航与数据传递) +6. [开发最佳实践与常见问题](#开发最佳实践与常见问题) + +## 首页(数据源概览) + +首页是datavines-ui的核心入口页面,主要功能是展示和管理数据源。用户可以通过该页面查看所有已配置的数据源,并进行创建、编辑、删除等操作。 + +页面布局采用ContentLayout作为整体容器,顶部为标题区域,包含页面标题和创建数据源的按钮。下方是搜索和视图切换区域,用户可以通过表单进行搜索,并在卡片视图和表格视图之间切换。内容区域根据用户选择的视图模式显示不同的组件。 + +在功能模块方面,首页提供了完整的数据源生命周期管理: +- **创建**:点击"创建数据源"按钮弹出模态框,用户可以填写数据源名称、类型及连接参数 +- **查看**:点击数据源名称或卡片可进入数据源详情页面 +- **编辑**:通过操作列的编辑按钮修改数据源配置 +- **删除**:通过操作列的删除按钮移除数据源,需二次确认 +- **元数据获取**:在卡片视图中,通过下拉菜单可以配置元数据获取任务 + +用户交互流程从数据源列表开始,用户可以选择查看、编辑或删除现有数据源,也可以创建新的数据源。创建或编辑数据源时,系统会根据选择的数据源类型动态加载相应的配置表单。 + +**页面来源** +- [Home/index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx) +- [Home/List/Table.tsx](file://datavines-ui\src\view\Main\Home\List\Table.tsx) +- [Home/List/Card.tsx](file://datavines-ui\src\view\Main\Home\List\Card.tsx) + +## 任务管理 + +任务管理功能位于数据源详情页面下的"任务"标签页中,主要负责数据质量检查任务的创建、编辑、执行监控等操作。 + +页面结构采用Tabs组件组织不同类型的检查任务,包括"质量检查"和"数据比对"两大类。每个任务类型下展示相应的任务列表,包含任务ID、名称、关联的数据库、表、列、调度表达式、执行统计等信息。 + +核心功能模块包括: +- **任务创建**:通过下拉菜单选择任务类型(质量检查或数据比对),点击"添加"按钮进入任务配置向导 +- **任务编辑**:点击操作列的编辑按钮修改现有任务配置 +- **立即执行**:点击"运行"按钮立即触发任务执行 +- **实例查看**:点击"查看"按钮进入任务执行实例页面 +- **配置预览**:点击"预览"按钮查看任务执行配置 +- **SLA关联**:将任务与SLA规则关联,实现告警管理 + +任务配置采用多标签页的向导式界面,包含: +1. **指标配置**:定义质量检查的具体指标和规则 +2. **调度配置**:设置任务的定时执行计划 +3. **SLA配置**:关联相应的SLA规则 +4. **配置文件**:查看和导出任务的JSON配置文件 + +用户交互流程从任务列表开始,用户可以创建新任务或编辑现有任务。创建任务时,系统会引导用户完成指标配置、调度设置等步骤。任务创建后,用户可以立即执行、查看执行历史或监控执行状态。 + +**页面来源** +- [HomeDetail/Jobs/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\index.tsx) +- [HomeDetail/Jobs/JobsList.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\JobsList.tsx) +- [HomeDetail/Jobs/useAddEditJobsModal/index.tsx](file://datavines-ui\src\view\Main\HomeDetail\Jobs\useAddEditJobsModal\index.tsx) + +## 告警管理 + +告警管理功能通过"告警"主菜单项访问,主要负责SLA(服务等级协议)的配置和通知设置。 + +SLA配置页面允许用户定义数据质量的阈值规则,当数据质量检查结果超出预设阈值时触发告警。通知设置页面则管理告警的发送方式和接收人。 + +在SLA设置页面中,用户可以: +- 查看和管理SLA规则列表 +- 为SLA规则配置通知方式(如邮件、钉钉等) +- 设置通知的接收人和发送条件 +- 查看通知历史和状态 + +通知设置页面的主要功能包括: +- **通知创建**:添加新的通知配置,选择通知类型(邮件、钉钉、飞书等) +- **通知编辑**:修改现有通知配置 +- **通知删除**:移除不再需要的通知配置 +- **测试连接**:验证通知配置的有效性 + +用户交互流程从告警主页面开始,用户可以查看所有SLA规则,点击特定SLA规则进入详细设置页面。在详细页面中,用户可以配置通知方式,添加或修改通知规则。 + +**页面来源** +- [Warning/SLAsSetting/index.tsx](file://datavines-ui\src\view\Main\Warning\SLAsSetting\index.tsx) +- [Warning/SLAsSetting/Notification.tsx](file://datavines-ui\src\view\Main\Warning\SLAsSetting\Notification.tsx) + +## 用户管理 + +用户管理功能通过"用户管理"主菜单项访问,主要负责工作空间和权限控制。 + +该功能模块允许管理员: +- 管理用户账户和权限 +- 配置工作空间的访问控制 +- 分配用户角色和权限 +- 管理API令牌 + +工作空间管理功能包括: +- 创建和删除工作空间 +- 配置工作空间的成员和权限 +- 管理工作空间级别的设置 + +权限控制系统基于角色的访问控制(RBAC)模型,支持细粒度的权限分配,确保数据安全和合规性。 + +**页面来源** +- [mainRouter.tsx](file://datavines-ui\src\router\mainRouter.tsx) + +## 页面导航与数据传递 + +datavines-ui的页面导航系统基于React Router实现,通过mainRouter.tsx和detailRouter.tsx两个路由配置文件管理应用的导航结构。 + +主路由配置(mainRouter.tsx)定义了顶级菜单项: +- 首页(/main/home) +- 告警(/main/warning) +- 错误数据管理(/main/errorDataManage) +- 用户管理(/main/userManage) +- 标签(/main/label) +- 配置(/main/config) +- 令牌管理(/main/tokenManager) + +详情路由配置(detailRouter.tsx)定义了数据源详情页面下的子页面: +- 仪表板(/main/detail/:id/dashboard) +- 编辑器(/main/detail/:id/editor) +- 任务(/main/detail/:id/jobs) +- 执行日志(/main/detail/:id/jobExecutionLogs) + +数据传递主要通过以下几种方式实现: +1. **URL参数**:使用路由参数传递数据源ID等关键信息 +2. **Redux状态管理**:通过store/index.ts中的Redux store管理全局状态,包括用户登录信息、工作空间ID等 +3. **组件props**:父组件向子组件传递数据和回调函数 +4. **Context API**:使用useContext等Hook共享组件树中的数据 + +页面间的数据流遵循单向数据流原则,从状态管理器到UI组件,确保数据的一致性和可预测性。 + +**页面来源** +- [mainRouter.tsx](file://datavines-ui\src\router\mainRouter.tsx) +- [detailRouter.tsx](file://datavines-ui\src\router\detailRouter.tsx) +- [store/index.ts](file://datavines-ui\src\store\index.ts) + +## 开发最佳实践与常见问题 + +### 开发最佳实践 + +1. **组件化设计**:遵循单一职责原则,将页面拆分为可复用的小组件 +2. **状态管理**:合理使用Redux管理全局状态,避免过度使用导致性能问题 +3. **类型安全**:充分利用TypeScript的类型系统,定义清晰的接口和类型 +4. **异步处理**:使用async/await处理异步操作,配合loading状态提升用户体验 +5. **国际化**:使用react-intl实现多语言支持,确保应用的国际化能力 + +### 常见问题解决方案 + +1. **数据源连接测试失败**: + - 检查网络连接和防火墙设置 + - 验证连接参数的正确性 + - 确认数据库服务是否正常运行 + +2. **任务执行失败**: + - 检查任务配置的正确性 + - 查看执行日志定位具体错误 + - 验证数据源连接状态 + +3. **页面加载缓慢**: + - 优化数据查询,添加适当的分页和筛选 + - 使用虚拟滚动处理大量数据 + - 懒加载非关键组件 + +4. **权限问题**: + - 检查用户角色和权限配置 + - 验证API令牌的有效性 + - 确认工作空间访问权限 + +5. **国际化文本缺失**: + - 检查语言包中是否包含相应的翻译 + - 确保组件正确使用FormattedMessage组件 + - 验证语言切换功能的实现 + +**页面来源** +- [Home/AddDataSource/index.tsx](file://datavines-ui\src\view\Main\Home\AddDataSource\index.tsx) +- [Home/List/MetaDataFetcher.tsx](file://datavines-ui\src\view\Main\Home\List\MetaDataFetcher.tsx) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\347\224\250\346\210\267\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\347\224\250\346\210\267\347\256\241\347\220\206.md" new file mode 100644 index 00000000..09539fb0 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\347\224\250\346\210\267\347\256\241\347\220\206.md" @@ -0,0 +1,121 @@ +# 用户管理 + + +**本文档引用的文件** +- [index.tsx](file://datavines-ui\src\view\Main\UserManage\index.tsx) +- [useAddUser.tsx](file://datavines-ui\src\view\Main\UserManage\useAddUser.tsx) +- [WorkSpaceSwitch\index.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\index.tsx) +- [useAddSpace.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\useAddSpace.tsx) +- [User.ts](file://datavines-ui\src\type\User.ts) +- [workSpace.ts](file://datavines-ui\src\type\workSpace.ts) +- [index.ts](file://datavines-ui\src\action\workSpace\index.tsx) +- [index.ts](file://datavines-ui\src\http\index.ts) +- [userReducer\index.ts](file://datavines-ui\src\store\userReducer\index.ts) +- [workSpaceReducer\index.ts](file://datavines-ui\src\store\workSpaceReducer\index.ts) +- [TokenManager\index.tsx](file://datavines-ui\src\view\Main\TokenManager\index.tsx) +- [CreateToken.tsx](file://datavines-ui\src\view\Main\TokenManager\CreateToken.tsx) +- [token.ts](file://datavines-ui\src\type\token.ts) + + +## 目录 +1. [用户管理页面布局与功能模块](#用户管理页面布局与功能模块) +2. [工作空间切换组件](#工作空间切换组件) +3. [用户添加与权限分配流程](#用户添加与权限分配流程) +4. [工作空间邀请机制](#工作空间邀请机制) +5. [令牌管理功能](#令牌管理功能) +6. [用户角色与权限控制](#用户角色与权限控制) +7. [安全认证与用户交互设计](#安全认证与用户交互设计) +8. [开发实现细节与最佳实践](#开发实现细节与最佳实践) + +## 用户管理页面布局与功能模块 + +用户管理页面位于 `datavines-ui` 的 `/main/userManage` 路由下,主要功能是展示当前工作空间中的用户列表,并提供添加、删除用户的操作入口。页面采用 Ant Design 的 Table 组件展示用户信息,包括用户名、邮箱、电话等字段。页面顶部设有“邀请用户”按钮,点击后弹出模态框进行用户添加操作。 + +用户数据通过分页方式从后端接口 `/workspace/userPage` 获取,支持分页切换。删除用户时通过 Popconfirm 组件进行二次确认,确保操作安全。 + +**页面来源** +- [index.tsx](file://datavines-ui\src\view\Main\UserManage\index.tsx#L1-L168) + +## 工作空间切换组件 + +工作空间切换组件位于页面头部,允许用户在多个工作空间之间切换。组件包含一个下拉选择器(CustomSelect),显示当前用户所属的所有工作空间列表。用户选择不同工作空间后,系统会更新当前上下文,并通过 Redux store 的 `workSpaceReducer` 保存新的工作空间 ID。 + +组件还提供“添加工作空间”按钮和操作菜单(通过 EllipsisOutlined 图标展开),支持编辑和删除当前工作空间。删除操作受条件限制:当工作空间数量大于1时才允许删除,防止用户误删唯一工作空间。 + +该组件通过 `useWatch` 监听路由变化,自动加载对应工作空间下的数据源列表,实现动态数据加载。 + +**组件来源** +- [WorkSpaceSwitch\index.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\index.tsx#L1-L191) +- [useAddSpace.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\useAddSpace.tsx#L1-L85) + +## 用户添加与权限分配流程 + +用户添加功能通过点击“邀请用户”按钮触发,弹出模态框。模态框使用 `FormRender` 组件渲染表单,包含用户名和邮箱两个必填字段。表单验证由 Ant Design 的 Form 组件完成,确保输入合法性。 + +提交表单时,前端调用 `/workspace/inviteUser` 接口,将用户名、邮箱和当前工作空间 ID 作为参数发送至后端。后端处理邀请逻辑,可能涉及权限分配。成功后刷新用户列表并提示“操作成功”。 + +权限分配逻辑在后端实现,前端仅提供邀请入口。用户被邀请后,默认获得该工作空间的访问权限,具体角色和权限由后端策略决定。 + +**流程来源** +- [useAddUser.tsx](file://datavines-ui\src\view\Main\UserManage\useAddUser.tsx#L1-L116) +- [index.tsx](file://datavines-ui\src\view\Main\UserManage\index.tsx#L1-L168) + +## 工作空间邀请机制 + +工作空间邀请机制通过 `/workspace/inviteUser` API 接口实现。前端收集被邀请用户的用户名和邮箱,连同当前工作空间 ID 一并提交。后端接收到请求后,验证用户是否存在,若存在则将其加入该工作空间,若不存在可选择创建新用户或发送注册邀请。 + +邀请成功后,被邀请用户将在其账户下看到新增的工作空间,并可根据权限进行相应操作。整个流程无需密码或敏感信息传递,确保安全性。 + +**机制来源** +- [useAddUser.tsx](file://datavines-ui\src\view\Main\UserManage\useAddUser.tsx#L72) +- [index.ts](file://datavines-ui\src\http\index.ts#L24-L51) + +## 令牌管理功能 + +令牌管理页面允许用户创建和管理访问令牌,用于 API 调用或其他自动化场景。页面展示令牌列表,包括过期时间、令牌值和更新时间。用户可创建新令牌或编辑现有令牌,设置其过期时间。 + +创建/编辑令牌时,使用 DatePicker 组件选择过期时间,提交后调用 `/token` 接口(POST 创建,PUT 更新)。删除令牌通过 `/token/${id}` DELETE 接口完成,操作前有二次确认提示。 + +令牌值在前端不显示明文,仅在创建时短暂展示,后续仅显示部分掩码信息,增强安全性。 + +**功能来源** +- [TokenManager\index.tsx](file://datavines-ui\src\view\Main\TokenManager\index.tsx#L1-L170) +- [CreateToken.tsx](file://datavines-ui\src\view\Main\TokenManager\CreateToken.tsx#L1-L106) + +## 用户角色与权限控制 + +系统通过 Redux store 中的 `userReducer` 和 `workSpaceReducer` 管理用户状态和工作空间上下文。`userReducer` 存储登录用户信息,包括 ID、用户名、邮箱、是否管理员等。`workSpaceReducer` 管理当前工作空间 ID 和工作空间列表。 + +权限控制主要在后端实现,前端根据用户角色(如管理员)动态渲染界面元素。例如,管理员可看到更多管理选项。工作空间级别的权限通过 `workspaceId` 参数传递,确保用户只能访问其所属工作空间的资源。 + +**控制来源** +- [userReducer\index.ts](file://datavines-ui\src\store\userReducer\index.ts#L1-L48) +- [workSpaceReducer\index.ts](file://datavines-ui\src\store\workSpaceReducer\index.ts#L1-L58) + +## 安全认证与用户交互设计 + +系统采用 Bearer Token 认证机制。用户登录后,Token 存储在 Redux store 和 sessionStorage 中。每次 HTTP 请求,`$http` 实例通过 requestInterceptor 自动添加 `Authorization` 头。后端验证 Token 有效性,若过期或无效,响应拦截器会重定向至登录页。 + +Token 刷新机制由响应拦截器实现:当后端返回新 Token 时,前端自动更新本地存储,实现无感刷新。敏感操作(删除用户、删除工作空间)均需二次确认,防止误操作。 + +国际化支持通过 `react-intl` 实现,界面文本根据用户语言偏好动态切换。 + +**设计来源** +- [index.ts](file://datavines-ui\src\http\index.ts#L9-L48) +- [userReducer\index.ts](file://datavines-ui\src\store\userReducer\index.ts#L4-L11) + +## 开发实现细节与最佳实践 + +1. **状态管理**:使用 Redux 集中管理应用状态,通过 `useSelector` 和 `useActions` 进行状态读取和更新,确保状态一致性。 +2. **组件复用**:`useAddUser` 和 `useCreateToken` 等自定义 Hook 封装了模态框和表单逻辑,实现高内聚低耦合。 +3. **类型安全**:使用 TypeScript 定义 `TUserItem`、`IWorkSpaceListItem` 等接口,提升代码可维护性。 +4. **HTTP 封装**:`$http` 实例统一处理请求/响应拦截,简化 API 调用。 +5. **性能优化**:使用 `React.memo` 和 `useImmutable` 避免不必要的渲染。 +6. **错误处理**:所有异步操作均包含 try-catch,确保异常不会导致应用崩溃。 +7. **用户体验**:加载状态、操作反馈、二次确认等细节提升交互体验。 + +**实现来源** +- [useAddUser.tsx](file://datavines-ui\src\view\Main\UserManage\useAddUser.tsx) +- [useAddSpace.tsx](file://datavines-ui\src\component\Header\WorkSpaceSwitch\useAddSpace.tsx) +- [index.ts](file://datavines-ui\src\http\index.ts) +- [userReducer\index.ts](file://datavines-ui\src\store\userReducer\index.ts) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\351\246\226\351\241\265\345\212\237\350\203\275.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\351\246\226\351\241\265\345\212\237\350\203\275.md" new file mode 100644 index 00000000..0b12b37a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/datavines-ui\346\250\241\345\235\227/\346\240\270\345\277\203\351\241\265\351\235\242\345\212\237\350\203\275/\351\246\226\351\241\265\345\212\237\350\203\275.md" @@ -0,0 +1,405 @@ +# 首页功能 + + +**本文档引用的文件** +- [index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx) +- [Card.tsx](file://datavines-ui\src\view\Main\Home\List\Card.tsx) +- [Table.tsx](file://datavines-ui\src\view\Main\Home\List\Table.tsx) +- [AddDataSource\index.tsx](file://datavines-ui\src\view\Main\Home\AddDataSource\index.tsx) +- [MetaDataFetcher.tsx](file://datavines-ui\src\view\Main\Home\List\MetaDataFetcher.tsx) +- [datasourceReducer\index.ts](file://datavines-ui\src\store\datasourceReducer\index.ts) +- [dataSource.ts](file://datavines-ui\src\type\dataSource.ts) +- [mainRouter.tsx](file://datavines-ui\src\router\mainRouter.tsx) +- [zh_CN.ts](file://datavines-ui\src\locale\zh_CN.ts) + + +## 目录 +1. [简介](#简介) +2. [页面布局结构](#页面布局结构) +3. [视图模式](#视图模式) +4. [数据源操作流程](#数据源操作流程) +5. [元数据采集和刷新机制](#元数据采集和刷新机制) +6. [组件开发实现细节](#组件开发实现细节) +7. [常见问题解决方案](#常见问题解决方案) + +## 简介 +datavines-ui的首页功能主要提供数据源概览页面,用户可以通过该页面查看、管理所有数据源。页面提供了卡片式和表格列表两种视图模式,支持数据源的添加、编辑、删除等操作,并集成了元数据采集和刷新功能。 + +**Section sources** +- [index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx#L1-L143) + +## 页面布局结构 +首页功能的页面布局主要由以下几个部分组成: + +1. **标题区域**:显示"数据源管理"标题和"创建数据源"按钮 +2. **搜索区域**:包含搜索表单和视图切换按钮 +3. **数据展示区域**:根据用户选择的视图模式显示数据源列表 +4. **模态框**:用于数据源的添加和编辑操作 + +页面采用ContentLayout组件作为容器,内部通过Flex布局组织各个区域。标题区域使用Title组件,右侧浮动显示创建按钮。搜索区域使用SearchForm组件进行搜索,右侧通过Radio.Group组件提供视图模式切换功能。 + +```mermaid +graph TD +A[首页容器 ContentLayout] --> B[标题区域] +A --> C[搜索区域] +A --> D[数据展示区域] +A --> E[模态框] +B --> B1[Title组件] +B --> B2[创建数据源按钮] +C --> C1[SearchForm组件] +C --> C2[视图切换Radio.Group] +D --> D1[卡片视图 CardList] +D --> D2[表格视图 TableList] +E --> E1[AddDataSource模态框] +``` + +**Diagram sources ** +- [index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx#L78-L139) + +**Section sources** +- [index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx#L78-L139) + +## 视图模式 +首页功能提供两种数据源展示视图模式:卡片式视图和表格列表视图。 + +### 卡片式视图 +卡片式视图以卡片形式展示每个数据源,每个卡片包含数据源名称、类型标签、更新时间和操作菜单。卡片采用响应式布局,每行显示4个卡片。 + +```mermaid +graph TD +A[卡片容器] --> B[数据源名称] +A --> C[类型标签] +A --> D[更新时间] +A --> E[操作菜单] +E --> E1[编辑] +E --> E2[删除] +E --> E3[元数据采集] +``` + +**Diagram sources ** +- [Card.tsx](file://datavines-ui\src\view\Main\Home\List\Card.tsx#L33-L134) + +### 表格列表视图 +表格列表视图以表格形式展示数据源信息,包含名称、类型、更新人、更新时间和操作列。表格支持分页和排序功能。 + +```mermaid +graph TD +A[表格] --> B[列: 名称] +A --> C[列: 类型] +A --> D[列: 更新人] +A --> E[列: 更新时间] +A --> F[列: 操作] +F --> F1[编辑] +F --> F2[删除] +``` + +**Diagram sources ** +- [Table.tsx](file://datavines-ui\src\view\Main\Home\List\Table.tsx#L20-L68) + +### 视图模式切换 +视图模式的切换通过Redux状态管理实现。用户选择视图模式后,状态存储在datasourceReducer中,根据tableType状态值决定显示哪种视图。 + +```mermaid +stateDiagram-v2 +[*] --> CARD +CARD --> TABLE : 用户切换到表格视图 +TABLE --> CARD : 用户切换到卡片视图 +CARD --> CARD : 显示卡片列表 +TABLE --> TABLE : 显示表格列表 +``` + +**Diagram sources ** +- [datasourceReducer\index.ts](file://datavines-ui\src\store\datasourceReducer\index.ts#L24-L30) +- [index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx#L115-L134) + +**Section sources** +- [Card.tsx](file://datavines-ui\src\view\Main\Home\List\Card.tsx#L1-L189) +- [Table.tsx](file://datavines-ui\src\view\Main\Home\List\Table.tsx#L1-L96) +- [datasourceReducer\index.ts](file://datavines-ui\src\store\datasourceReducer\index.ts#L1-L68) + +## 数据源操作流程 +首页功能支持数据源的添加、编辑和删除操作,这些操作通过统一的模态框组件实现。 + +### 添加数据源 +添加数据源的流程如下: +1. 用户点击"创建数据源"按钮 +2. 显示添加数据源模态框 +3. 用户填写数据源信息并测试连接 +4. 用户确认保存,发送POST请求创建数据源 +5. 刷新数据源列表 + +```mermaid +sequenceDiagram +participant User as 用户 +participant UI as 前端界面 +participant API as 后端API +User->>UI : 点击创建数据源按钮 +UI->>UI : 显示添加模态框 +User->>UI : 填写数据源信息 +User->>UI : 点击测试链接 +UI->>API : POST /datasource/test +API-->>UI : 返回测试结果 +UI->>User : 显示测试结果 +User->>UI : 点击确认 +UI->>API : POST /datasource +API-->>UI : 返回创建结果 +UI->>UI : 刷新数据源列表 +UI-->>User : 显示操作结果 +``` + +**Diagram sources ** +- [AddDataSource\index.tsx](file://datavines-ui\src\view\Main\Home\AddDataSource\index.tsx#L137-L158) + +### 编辑数据源 +编辑数据源的流程与添加类似,主要区别在于: +1. 模态框初始化时会加载现有数据源信息 +2. 保存时发送PUT请求更新数据源 + +```mermaid +sequenceDiagram +participant User as 用户 +participant UI as 前端界面 +participant API as 后端API +User->>UI : 点击编辑按钮 +UI->>UI : 加载数据源信息并显示模态框 +User->>UI : 修改数据源信息 +User->>UI : 点击测试链接 +UI->>API : POST /datasource/test +API-->>UI : 返回测试结果 +UI->>User : 显示测试结果 +User->>UI : 点击确认 +UI->>API : PUT /datasource +API-->>UI : 返回更新结果 +UI->>UI : 刷新数据源列表 +UI-->>User : 显示操作结果 +``` + +**Diagram sources ** +- [AddDataSource\index.tsx](file://datavines-ui\src\view\Main\Home\AddDataSource\index.tsx#L142-L149) + +### 删除数据源 +删除数据源采用确认删除模式,确保用户操作的准确性。 + +```mermaid +flowchart TD +A[用户点击删除按钮] --> B{显示确认对话框} +B --> C[用户点击确定] +C --> D[发送DELETE请求] +D --> E[刷新数据源列表] +B --> F[用户点击取消] +F --> G[取消删除操作] +``` + +**Diagram sources ** +- [index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx#L68-L76) +- [Card.tsx](file://datavines-ui\src\view\Main\Home\List\Card.tsx#L82-L92) +- [Table.tsx](file://datavines-ui\src\view\Main\Home\List\Table.tsx#L58-L64) + +**Section sources** +- [AddDataSource\index.tsx](file://datavines-ui\src\view\Main\Home\AddDataSource\index.tsx#L128-L217) +- [index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx#L65-L77) + +## 元数据采集和刷新机制 +首页功能集成了元数据采集和刷新机制,用户可以通过界面操作触发元数据的采集和刷新。 + +### 元数据采集流程 +当用户点击"元数据管理"操作时,系统会打开元数据采集调度管理模态框,用户可以配置采集任务的调度策略。 + +```mermaid +sequenceDiagram +participant User as 用户 +participant UI as 前端界面 +participant API as 后端API +User->>UI : 点击元数据管理 +UI->>UI : 显示元数据采集调度管理模态框 +User->>UI : 配置调度策略 +User->>UI : 点击保存 +UI->>API : POST /common-task/schedule/createOrUpdate +API-->>UI : 返回创建结果 +UI->>User : 显示操作结果 +``` + +**Diagram sources ** +- [MetaDataFetcher.tsx](file://datavines-ui\src\view\Main\Home\List\MetaDataFetcher.tsx#L139-L150) + +### 元数据立即刷新 +用户还可以选择立即执行元数据刷新,无需等待调度。 + +```mermaid +sequenceDiagram +participant User as 用户 +participant UI as 前端界面 +participant API as 后端API +User->>UI : 点击立即执行 +UI->>API : POST /catalog/refresh +API-->>UI : 返回执行结果 +UI->>User : 显示执行结果 +``` + +**Diagram sources ** +- [MetaDataFetcher.tsx](file://datavines-ui\src\view\Main\Home\List\MetaDataFetcher.tsx#L539-L541) + +### 用户交互设计 +元数据采集和刷新的用户交互设计考虑了以下几点: +1. **操作可见性**:在每个数据源卡片的操作菜单中提供"元数据管理"选项 +2. **操作确认**:删除操作需要二次确认,防止误操作 +3. **操作反馈**:所有操作都有明确的成功或失败提示 +4. **状态同步**:操作完成后自动刷新数据源列表,确保界面状态与后端一致 + +**Section sources** +- [MetaDataFetcher.tsx](file://datavines-ui\src\view\Main\Home\List\MetaDataFetcher.tsx#L1-L175) +- [Card.tsx](file://datavines-ui\src\view\Main\Home\List\Card.tsx#L97-L106) + +## 组件开发实现细节 +首页功能的各个组件通过React Hooks和Redux进行状态管理,实现了组件间的解耦和复用。 + +### 状态管理 +使用Redux管理视图模式状态,定义了tableType状态和对应的action。 + +```mermaid +classDiagram +class DatasourceReducer { ++tableType : 'CARD' | 'TABLE' ++modeType : string ++entityUuid : string ++dsiabledEdit : DsiabledEdit | null ++editType : boolean +} +class datasourceActionsMap { ++setDatasourceType(tableType : TTableType) ++setDatasourceModeType(modeType : string) +} +DatasourceReducer --> datasourceActionsMap : "使用" +``` + +**Diagram sources ** +- [datasourceReducer\index.ts](file://datavines-ui\src\store\datasourceReducer\index.ts#L9-L67) + +### 数据交互 +通过$http服务与后端API进行数据交互,封装了常用的HTTP方法。 + +```mermaid +classDiagram +class $http { ++get(url, params) ++post(url, data) ++put(url, data) ++delete(url) +} +class index.tsx { ++getData() ++onSearch() ++onPageChange() ++onEdit() ++onDelete() +} +index.tsx --> $http : "使用" +``` + +**Diagram sources ** +- [http\index.ts](file://datavines-ui\src\http\index.ts#L24-L50) +- [index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx#L36-L76) + +### 类型定义 +使用TypeScript定义了数据源相关的类型,确保类型安全。 + +```mermaid +classDiagram +class IDataSourceListItem { ++id : number ++name : string ++param : string ++type : string ++updater : string ++updateTime : string +} +class IDataSourceList { ++total : number ++list : IDataSourceListItem[] +} +class ICreateDataSourceItem { ++field : string ++props : ICreateDataSourceProps ++type : string ++title : string ++value : string ++validate : ICreateDataSourceValidate[] ++options? : CreateDataSourceDynamicItemOption[] +} +IDataSourceList --> IDataSourceListItem : "包含" +``` + +**Diagram sources ** +- [dataSource.ts](file://datavines-ui\src\type\dataSource.ts#L36-L50) + +**Section sources** +- [datasourceReducer\index.ts](file://datavines-ui\src\store\datasourceReducer\index.ts#L1-L68) +- [http\index.ts](file://datavines-ui\src\http\index.ts#L1-L51) +- [dataSource.ts](file://datavines-ui\src\type\dataSource.ts#L1-L50) + +## 常见问题解决方案 +### 视图模式不保存 +问题:用户切换视图模式后,刷新页面又恢复到默认模式。 + +解决方案:将视图模式状态存储在localStorage中,页面加载时优先读取localStorage中的值。 + +```typescript +// 在datasourceReducer中添加localStorage支持 +const initialState: DatasourceReducer = { + tableType: localStorage.getItem('datasourceViewMode') || 'CARD', + modeType: '', + entityUuid: '', + dsiabledEdit: null, + editType: false, +}; + +// 在setDatasourceType action中保存到localStorage +export const datasourceActionsMap = { + setDatasourceType: (tableType: TTableType) => (dispatch: TDispatch) => { + localStorage.setItem('datasourceViewMode', tableType); + dispatch({ + type: 'save_datasource_type', + payload: tableType, + }); + }, +}; +``` + +### 数据源列表加载缓慢 +问题:当数据源数量较多时,列表加载缓慢。 + +解决方案:优化分页参数,默认pageSize从20调整为50,减少请求次数。 + +```typescript +// 在index.tsx中调整分页参数 +const [pageParams, setPageParams] = useState({ + pageNumber: 1, + pageSize: 50, // 从20调整为50 +}); +``` + +### 元数据采集任务重复创建 +问题:用户多次点击"保存"按钮,导致创建多个相同的采集任务。 + +解决方案:在保存按钮上添加loading状态,防止重复提交。 + +```typescript +// 在ScheduleContainer组件中使用useLoading +const globalSetLoading = useLoading(); +const onSave = async (type:string = 'add') => { + getValues(async (params: any) => { + globalSetLoading(true); // 设置loading状态 + try { + // 保存逻辑 + } catch (error) { + } finally { + globalSetLoading(false); // 清除loading状态 + } + }); +}; +``` + +**Section sources** +- [datasourceReducer\index.ts](file://datavines-ui\src\store\datasourceReducer\index.ts#L24-L30) +- [index.tsx](file://datavines-ui\src\view\Main\Home\index.tsx#L32-L35) +- [MetaDataFetcher.tsx](file://datavines-ui\src\view\Main\Home\List\MetaDataFetcher.tsx#L457-L578) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/\346\250\241\345\235\227\350\257\246\350\247\243.md" "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/\346\250\241\345\235\227\350\257\246\350\247\243.md" new file mode 100644 index 00000000..32bef653 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\250\241\345\235\227\350\257\246\350\247\243/\346\250\241\345\235\227\350\257\246\350\247\243.md" @@ -0,0 +1,281 @@ +# 模块详解 + + +**本文档引用的文件** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java) +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + + +## 目录 +1. [server模块](#server模块) +2. [engine模块](#engine模块) +3. [connector模块](#connector模块) +4. [metric模块](#metric模块) +5. [notification模块](#notification模块) +6. [registry模块](#registry模块) +7. [ui模块](#ui模块) + +## server模块 + +server模块是DataVines的核心服务组件,负责系统的整体协调和调度。该模块基于Spring Boot框架构建,作为整个系统的控制中心,管理着数据质量检查任务的生命周期。 + +DataVinesServer类是服务的主入口点,通过SpringBootApplication注解启动应用。该模块初始化了多个关键组件:JobExecuteManager负责任务执行管理,CommonTaskManager处理通用任务调度,RegistryHolder管理注册中心连接。服务启动时,通过PluginLoader动态加载注册中心插件(如MySQL或ZooKeeper),并根据配置初始化相应的注册实现。 + +该模块还实现了优雅关闭机制,通过Runtime.getRuntime().addShutdownHook注册关闭钩子,在接收到关闭信号时,按顺序关闭各个组件,确保资源的正确释放。服务通过Register组件与注册中心交互,实现服务注册、心跳检测和故障转移功能。JobScheduler组件负责调度数据质量检查作业,而CommonTaskScheduler则处理系统级的周期性任务。 + +**模块职责**: +- 系统启动和初始化 +- 服务注册与发现 +- 任务调度与协调 +- 故障转移处理 +- 资源管理和优雅关闭 + +**接口与配置**: +- 通过application.yaml进行配置 +- 支持MySQL和ZooKeeper作为注册中心 +- 提供RESTful API接口供前端调用 +- 通过环境变量支持Kubernetes模式部署 + +**使用方法**: +通过bin目录下的启动脚本启动服务,系统会自动读取配置文件并初始化所有组件。开发者可以通过扩展SPI接口来定制特定功能。 + +**模块扩展指导**: +开发者可以通过实现SPI接口来扩展server模块的功能,如添加新的任务类型或集成不同的注册中心。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L1-L160) + +## engine模块 + +engine模块是DataVines的执行引擎,负责数据质量检查任务的具体执行。该模块采用插件化架构,支持多种执行环境和计算框架。 + +BaseDataVinesBootstrap是执行引擎的基类,定义了任务执行的通用流程:解析配置、验证配置、准备执行环境和执行任务。引擎通过ConfigParser解析配置文件,获取数据源(source)、转换(transform)和接收器(sink)等组件。执行过程包含配置验证阶段,确保所有组件的配置都有效后才开始执行。 + +RuntimeEnvironment接口定义了执行环境的契约,不同的计算框架(如Spark、Flink)可以实现此接口来提供特定的执行能力。Execution接口则代表具体的执行实例,负责协调数据处理流程。引擎支持本地执行模式和分布式执行模式,通过SPI机制动态加载相应的执行器。 + +EngineConstants类定义了引擎使用的常量,如输入表、输出表和临时表的名称,确保各组件之间的协调一致。 + +**模块职责**: +- 任务执行流程管理 +- 执行环境抽象 +- 配置解析与验证 +- 执行器管理 +- 错误处理与日志记录 + +**接口与配置**: +- 支持JSON格式的配置文件 +- 通过SPI机制扩展执行环境 +- 提供组件生命周期管理接口 +- 支持多种计算框架集成 + +**使用方法**: +通过命令行参数指定配置文件路径来启动执行引擎,系统会自动选择合适的执行器并执行任务。 + +**性能优化建议**: +- 合理配置执行器资源 +- 优化数据处理流程 +- 使用适当的并行度 +- 监控执行性能并调整参数 + +**模块扩展指导**: +开发者可以实现RuntimeEnvironment接口来支持新的计算框架,或实现Execution接口来定制执行逻辑。 + +**Section sources** +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java#L1-L129) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java#L1-L29) +- [EngineConstants.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java#L1-L33) + +## connector模块 + +connector模块负责与各种数据源的连接和交互,提供统一的数据访问接口。该模块采用适配器模式,为不同的数据库和数据系统提供一致的访问方式。 + +Connector接口是连接器的核心,定义了获取数据库、表、列等元数据的方法,以及测试连接的功能。每个具体的数据库连接器(如MySQL、PostgreSQL、Hive等)都实现这个接口。连接器通过DataSourceClient接口获取数据源连接,该接口支持从不同的配置形式(如BaseJdbcDataSourceInfo、Map或Properties)创建数据源。 + +模块采用插件化设计,新的连接器可以通过实现Connector接口并注册到系统中。连接器不仅支持基本的CRUD操作,还支持复杂的元数据查询和SQL执行。对于支持JDBC的数据库,系统提供了JdbcConnector基类,简化了JDBC连接器的开发。 + +**模块职责**: +- 数据源连接管理 +- 元数据获取 +- SQL执行 +- 连接池管理 +- 数据库方言处理 + +**接口与配置**: +- 支持JDBC、MongoDB、文件等多种数据源 +- 通过连接字符串和认证信息配置 +- 支持SSL连接 +- 可配置连接池参数 + +**使用方法**: +在配置中指定数据源类型和连接参数,系统会自动选择合适的连接器并建立连接。 + +**最佳实践**: +- 使用连接池提高性能 +- 合理设置连接超时 +- 定期测试连接可用性 +- 使用参数化查询防止SQL注入 + +**模块扩展指导**: +开发者可以实现Connector接口来支持新的数据源,或扩展JdbcConnector来支持新的JDBC兼容数据库。 + +**Section sources** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#L1-L73) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java#L1-L48) + +## metric模块 + +metric模块是DataVines的数据质量度量核心,定义了各种数据质量检查指标和验证规则。该模块采用策略模式,为不同类型的数据质量检查提供灵活的实现方式。 + +SqlMetric接口是度量的核心,定义了获取实际值、无效项目和配置验证等方法。每种数据质量指标(如列空值检查、列唯一性检查等)都实现这个接口。模块支持多种度量类型,通过MetricType枚举定义,包括单表检查、单表自定义SQL检查、多表准确性和多表值比较等。 + +度量插件通过SPI机制注册到系统中,可以在运行时动态加载。每个度量实现都提供了配置项定义,系统会根据这些定义生成用户界面。度量结果通过ResultFormula接口进行计算和比较,支持多种计算方式,如计数、百分比、差值等。 + +**模块职责**: +- 数据质量指标定义 +- 度量规则实现 +- 结果计算与比较 +- 配置验证 +- 问题描述生成 + +**接口与配置**: +- 支持多种数据类型适配 +- 提供国际化支持 +- 可配置预期值策略 +- 支持自定义SQL +- 提供配置项验证 + +**使用方法**: +在数据质量检查任务中选择合适的度量类型,配置相应的参数,系统会自动执行检查并生成结果。 + +**性能优化建议**: +- 优化度量SQL查询 +- 合理设置采样率 +- 使用索引提高查询性能 +- 批量执行相关度量 + +**模块扩展指导**: +开发者可以实现SqlMetric接口来创建新的数据质量检查规则,或扩展现有度量以支持新的功能。 + +**Section sources** +- [SqlMetric.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java#L1-L112) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java#L1-L71) + +## notification模块 + +notification模块负责系统通知和告警功能,确保数据质量检查结果能够及时传达给相关人员。该模块采用发布-订阅模式,支持多种通知渠道。 + +NotificationManager是通知模块的核心组件,负责管理通知发送器和处理通知请求。模块支持多种通知插件,如钉钉、企业微信、邮件和飞书等,通过SPI机制动态加载。通知内容可以根据模板生成,支持变量替换和格式化。 + +当数据质量检查任务完成或出现异常时,系统会生成相应的通知消息。通知可以基于SLA(服务级别协议)配置,当检查结果超出预设阈值时触发告警。模块还支持通知去重和频率控制,避免重复通知。 + +**模块职责**: +- 通知发送 +- 告警管理 +- 通知渠道集成 +- 消息模板管理 +- 发送状态跟踪 + +**接口与配置**: +- 支持多种通知渠道 +- 可配置通知模板 +- 支持条件通知 +- 可设置通知频率 +- 提供发送结果反馈 + +**使用方法**: +在系统配置中启用所需的通知插件,配置相应的凭证和参数,然后在任务中关联通知规则。 + +**最佳实践**: +- 合理设置告警阈值 +- 使用分级通知策略 +- 定期测试通知通道 +- 监控通知发送成功率 + +**模块扩展指导**: +开发者可以实现通知SPI接口来支持新的通知渠道,或扩展消息处理逻辑以支持复杂的业务场景。 + +**Section sources** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +## registry模块 + +registry模块提供服务注册与发现功能,支持分布式环境下的节点协调。该模块采用SPI架构,支持多种注册中心实现。 + +Registry接口定义了注册中心的核心功能,包括初始化、获取锁、订阅变更和获取活跃节点列表等。目前支持MySQL和ZooKeeper两种实现方式。MySQL注册中心利用数据库的行级锁实现分布式锁,而ZooKeeper注册中心则利用ZooKeeper的临时节点和监听机制。 + +注册模块在系统启动时初始化,负责节点的注册和心跳维护。当节点加入或离开集群时,其他节点能够及时感知并做出相应处理。模块还支持故障转移功能,当主节点失效时,能够自动选举新的主节点继续服务。 + +**模块职责**: +- 服务注册与发现 +- 分布式锁管理 +- 节点状态监控 +- 故障转移处理 +- 配置同步 + +**接口与配置**: +- 支持MySQL和ZooKeeper +- 可配置心跳间隔 +- 支持连接重试 +- 提供连接状态监听 +- 可设置锁超时时间 + +**使用方法**: +在配置文件中指定注册中心类型和连接参数,系统会自动选择合适的实现并初始化。 + +**性能优化建议**: +- 合理设置心跳间隔 +- 优化注册中心性能 +- 使用连接池 +- 监控注册中心状态 + +**模块扩展指导**: +开发者可以实现Registry接口来支持新的注册中心,如etcd或Consul。 + +**Section sources** +- [Registry.java](file://datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java#L1-L44) + +## ui模块 + +ui模块是DataVines的前端用户界面,基于React框架构建,提供直观的操作体验。该模块采用组件化设计,将复杂的用户界面分解为可重用的组件。 + +前端应用从index.tsx文件启动,使用React的createRoot方法渲染应用。界面采用模块化布局,包括头部、菜单、内容区域等部分。通过Redux管理应用状态,确保数据的一致性和可预测性。模块支持多语言,通过locale目录下的文件实现国际化。 + +UI与后端通过HTTP API进行通信,使用axios进行请求处理。界面提供了数据源管理、任务配置、监控告警等主要功能。通过Monaco编辑器组件提供SQL编辑功能,支持语法高亮和智能提示。 + +**模块职责**: +- 用户界面展示 +- 用户交互处理 +- 数据可视化 +- 表单验证 +- 状态管理 + +**接口与配置**: +- 支持响应式设计 +- 提供主题切换 +- 支持多语言 +- 可配置布局 +- 提供访问控制 + +**使用方法**: +通过构建工具(如webpack)打包前端资源,部署到Web服务器或与后端服务集成。 + +**最佳实践**: +- 优化页面加载性能 +- 提供良好的用户体验 +- 确保界面一致性 +- 实现适当的错误处理 + +**模块扩展指导**: +开发者可以创建新的React组件来扩展界面功能,或修改现有组件以满足特定需求。 + +**Section sources** +- [index.tsx](file://datavines-ui/src/index.tsx#L1-L11) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/Docker Compose\351\203\250\347\275\262.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/Docker Compose\351\203\250\347\275\262.md" new file mode 100644 index 00000000..94ea0c7f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/Docker Compose\351\203\250\347\275\262.md" @@ -0,0 +1,298 @@ +# Docker Compose部署 + + +**本文引用的文件列表** +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [.env](file://deploy/compose/.env) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [datavines.yaml](file://deploy/k8s/datavines.yaml) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能与资源建议](#性能与资源建议) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本指南面向希望使用 docker-compose 快速搭建完整 DataVines 环境的用户。文档将逐项解析 docker-compose.yaml 的服务定义(含 datavines-server、数据库等),说明 .env 文件的环境变量配置方式,并给出网络、数据卷、服务依赖、日志聚合、服务间通信与健康检查的实践建议。同时提供生产环境部署建议,包括资源限制、重启策略与监控集成。 + +## 项目结构 +DataVines 提供了多套部署方式,其中与本指南直接相关的是 compose 部署目录与 server 端配置: +- compose 部署:包含 docker-compose.yaml 与 .env +- server 端配置:包含 Spring Boot 的 application.yaml 与日志配置 server-logback.xml +- Kubernetes 部署示例:用于对比与参考(非本指南重点) + +```mermaid +graph TB +subgraph "本地开发/测试环境" +DC["docker-compose.yaml"] +ENV[".env"] +NET["自定义桥接网络
datavines"] +end +subgraph "应用服务" +DV["datavines-server 容器"] +DB["数据库容器需自行补充"] +end +DC --> DV +ENV --> DV +NET --> DV +DV -. "通过网络访问" .-> DB +``` + +图表来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) + +章节来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) + +## 核心组件 +- datavines-server 容器 + - 基于镜像 datavines:dev 启动 + - 暴露端口 5600 + - 使用 .env 注入环境变量 + - 使用自定义桥接网络 datavines + - 设置特权模式与重启策略 +- 数据库 + - 当前 compose 文件未内置数据库服务,需在实际环境中补充 MySQL 或 PostgreSQL 容器,并确保连接信息正确 +- 网络 + - 自定义桥接网络 datavines,子网为 172.18.0.0/24 +- 日志 + - server 端使用 server-logback.xml 输出控制台、作业日志与服务日志 + +章节来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L69-L83) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L33-L85) + +## 架构总览 +下图展示了基于 docker-compose 的典型部署拓扑:datavines-server 通过自定义网络与数据库容器互通;日志由 server-logback.xml 聚合输出到控制台与文件。 + +```mermaid +graph TB +subgraph "Compose 网络" +N1["datavines 网络
172.18.0.0/24"] +end +subgraph "服务" +S1["datavines-server 容器
端口 5600"] +S2["数据库容器
MySQL/PostgreSQL"] +end +N1 --> S1 +N1 --> S2 +S1 -. "JDBC 连接" .-> S2 +``` + +图表来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L14-L19) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L39) + +## 详细组件分析 + +### 组件一:datavines-server 服务定义 +- 镜像与端口映射 + - 使用镜像 datavines:dev + - 将宿主机 5600 映射到容器 5600 +- 环境变量注入 + - 通过 env_file 引用 .env 文件 +- 安全与稳定性 + - privileged: true(允许特权模式) + - restart: unless-stopped(除非手动停止,否则持续重启) +- 网络 + - 加入自定义网络 datavines + +```mermaid +flowchart TD +Start(["启动 datavines-server"]) --> LoadEnv["加载 .env 环境变量"] +LoadEnv --> ApplyCfg["Spring Boot 应用启动
读取 application.yaml"] +ApplyCfg --> NetJoin["加入自定义网络 datavines"] +NetJoin --> PortBind["绑定端口 5600"] +PortBind --> Ready(["服务就绪"]) +``` + +图表来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L3-L13) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L69-L71) + +章节来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L3-L13) + +### 组件二:.env 环境变量配置 +- spring.profiles.active=mysql:激活 MySQL 配置文件段 +- spring.datasource.url:数据库连接 URL(当前指向 127.0.0.1,需在 compose 中改为数据库容器名或网络别名) +- spring.datasource.username/password:数据库账号密码 +- spring.datasource.driver-class-name:驱动类名(MySQL) + +```mermaid +flowchart TD +A[".env 文件"] --> B["SPRING_PROFILES_ACTIVE=mysql"] +A --> C["SPRING_DATASOURCE_URL"] +A --> D["SPRING_DATASOURCE_USERNAME"] +A --> E["SPRING_DATASOURCE_PASSWORD"] +A --> F["SPRING_DATASOURCE_DRIVER-CLASS_NAME"] +B --> G["激活 application.yaml 中的 mysql 配置段"] +C --> H["应用侧 JDBC 连接数据库"] +``` + +图表来源 +- [.env](file://deploy/compose/.env#L1-L5) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L84-L96) + +章节来源 +- [.env](file://deploy/compose/.env#L1-L5) + +### 组件三:数据库服务(补充说明) +- 当前 docker-compose.yaml 未包含数据库服务,需要在实际部署时添加数据库容器,并确保: + - 数据库容器名称或网络别名为 application.yaml 中的 spring.datasource.url 所指向的目标 + - 数据库初始化 SQL 已执行(仓库提供 MySQL 初始化脚本) +- 可选方案 + - 在 docker-compose.yaml 中新增数据库服务(例如 MySQL/PostgreSQL) + - 使用外部数据库实例(需调整 .env 与 application.yaml 中的连接参数) + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L39) +- [scripts/sql/datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +### 组件四:网络与服务间通信 +- 自定义桥接网络 + - 使用 driver: bridge 与 IPAM 子网 172.18.0.0/24 +- 服务间通信 + - datavines-server 通过网络访问数据库容器(建议使用容器名或网络别名为连接目标) + - 如需对外暴露 Web 界面,保持 5600 端口映射即可 + +章节来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L14-L19) + +### 组件五:日志聚合与输出 +- server 端日志 + - 控制台输出与滚动文件输出 + - 作业执行日志按任务唯一标识落盘 +- 日志位置 + - 日志根目录由日志配置决定(默认可挂载卷至宿主机持久化) + +```mermaid +flowchart TD +L1["应用启动"] --> L2["server-logback.xml 生效"] +L2 --> L3["STDOUT 控制台输出"] +L2 --> L4["datavines-server.log 滚动文件"] +L2 --> L5["作业日志按任务唯一标识落盘"] +``` + +图表来源 +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L33-L85) + +章节来源 +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L33-L85) + +### 组件六:健康检查(建议) +- 当前 compose 未配置健康检查 +- 建议在生产环境为 datavines-server 添加健康检查,例如: + - 对外暴露的健康端点(如 /actuator/health) + - 使用 healthcheck 字段探测端口与路径 +- 参考 K8s 示例中对容器安全上下文与重启策略的处理,便于在 compose 中对齐 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L31-L60) + +## 依赖关系分析 +- 组件耦合 + - datavines-server 依赖数据库连接(由 .env 与 application.yaml 共同决定) + - 网络由 docker-compose 管理,datavines-server 通过网络访问数据库 +- 外部依赖 + - 数据库驱动与连接池(HikariCP)由 application.yaml 配置 + - Spring Profile 切换(mysql/postgresql)由 .env 指定 + +```mermaid +graph LR +ENV[".env"] --> APP["application.yaml"] +APP --> DB["数据库"] +DC["docker-compose.yaml"] --> DV["datavines-server"] +DV --> NET["自定义网络"] +NET --> DB +``` + +图表来源 +- [.env](file://deploy/compose/.env#L1-L5) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L39) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L14-L19) + +章节来源 +- [.env](file://deploy/compose/.env#L1-L5) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L39) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L14-L19) + +## 性能与资源建议 +- 资源限制(compose 层面) + - 可在 docker-compose.yaml 中为 datavines-server 容器设置 CPU/内存限制,避免资源争用 + - 建议结合业务规模与并发度评估,逐步调优 +- 重启策略 + - 当前使用 unless-stopped,适合开发/测试场景 + - 生产建议使用 on-failure 或 no,并配合外部编排系统进行更精细的恢复策略 +- 连接池与线程 + - application.yaml 中已配置 HikariCP 连接池参数,可根据数据库承载能力与请求量微调 + - Quartz 线程池大小与集群参数也影响任务调度性能 +- 日志轮转 + - server-logback.xml 已配置滚动策略,建议结合磁盘容量与保留周期进行调整 + +章节来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L3-L13) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L23-L39) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L61-L77) + +## 故障排查指南 +- 数据库连接失败 + - 检查 .env 中 spring.datasource.url 是否指向正确的数据库容器名或网络别名 + - 确认数据库已初始化并创建数据库名 +- 端口冲突 + - 若宿主机 5600 已被占用,修改映射端口或释放端口 +- 权限问题 + - datavines-server 使用 privileged: true,若在受限环境中需谨慎评估 +- 日志定位 + - 查看 server-logback.xml 配置的日志输出位置,确认是否挂载了持久化卷 +- 健康检查缺失 + - 生产环境建议增加健康检查,以便自动发现与恢复异常状态 + +章节来源 +- [.env](file://deploy/compose/.env#L1-L5) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L3-L13) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L33-L85) + +## 结论 +通过 docker-compose 可快速搭建 DataVines 的基础运行环境。当前 compose 文件聚焦于 datavines-server 与网络配置,数据库需另行补充。建议在生产环境中完善健康检查、资源限制与监控集成,并根据业务规模优化连接池与线程配置,以获得稳定高效的运行体验。 + +## 附录 + +### A. 环境变量清单(来自 .env) +- SPRING_PROFILES_ACTIVE:激活的 Spring Profile(mysql) +- SPRING_DATASOURCE_URL:数据库连接 URL(注意需指向数据库容器名或网络别名) +- SPRING_DATASOURCE_USERNAME:数据库用户名 +- SPRING_DATASOURCE_PASSWORD:数据库密码 +- SPRING_DATASOURCE_DRIVER-CLASS_NAME:数据库驱动类名(MySQL) + +章节来源 +- [.env](file://deploy/compose/.env#L1-L5) + +### B. 关键配置要点(来自 application.yaml) +- 数据源:driver-class-name、url、username、password、HikariCP 参数 +- Quartz:集群模式、线程池大小、表前缀等 +- Server:端口 5600 +- Management:指标暴露(生产建议精细化控制) + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) + +### C. 对比参考:Kubernetes 部署(非本指南重点) +- Deployment 中包含容器命令、环境变量、安全上下文与重启策略 +- Service 暴露 5600 端口 +- Ingress 配置域名与路径 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L112) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/Docker\351\203\250\347\275\262.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/Docker\351\203\250\347\275\262.md" new file mode 100644 index 00000000..956cd5e1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/Docker\351\203\250\347\275\262.md" @@ -0,0 +1,279 @@ +# Docker部署 + + +**本文引用的文件列表** +- [Dockerfile](file://deploy/docker/Dockerfile) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [.env](file://deploy/compose/.env) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能与资源考虑](#性能与资源考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录:构建与运行最佳实践](#附录构建与运行最佳实践) + +## 简介 +本指南面向希望在Docker环境中部署DataVines的用户,系统性讲解如何基于仓库提供的Dockerfile构建DataVines镜像并运行容器。内容涵盖: +- Dockerfile逐层解析(基础镜像、依赖安装、文件复制、端口暴露、启动命令) +- 如何通过环境变量覆盖application.yaml中的配置(数据库连接、服务端口等) +- 构建镜像与运行容器的完整命令及最佳实践(数据卷挂载、网络配置、资源限制) +- 镜像优化与安全配置建议 + +## 项目结构 +与Docker部署直接相关的目录与文件如下: +- 部署脚本与编排:deploy/docker/Dockerfile、deploy/compose/docker-compose.yaml、deploy/compose/.env +- 应用配置:datavines-server/src/main/resources/application.yaml +- 打包产物装配:datavines-dist/src/main/assembly/datavines-bin.xml +- 启动脚本:bin/datavines-daemon.sh + +```mermaid +graph TB +subgraph "部署与打包" +DF["Dockerfile"] +DC["docker-compose.yaml"] +ENV[".env"] +BINXML["datavines-bin.xml"] +end +subgraph "应用配置" +APPYML["application.yaml"] +end +subgraph "启动脚本" +DAEMON["datavines-daemon.sh"] +end +DF --> BINXML +DF --> DAEMON +DC --> ENV +DC --> DF +APPYML --> DAEMON +``` + +图表来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L1-L150) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +章节来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L1-L150) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +## 核心组件 +- Dockerfile:定义镜像构建流程,包含基础镜像、时区与语言设置、tini入口进程、打包产物复制与解压、权限修正、端口暴露、容器启动命令。 +- docker-compose.yaml:定义服务、端口映射、环境文件、重启策略、网络与子网。 +- .env:提供Spring Profile与数据库连接等环境变量,用于覆盖application.yaml中的默认值。 +- application.yaml:应用默认配置(数据库驱动、URL、用户名、密码、Quartz、Server端口等)。 +- datavines-bin.xml:打包装配清单,决定最终二进制包中包含哪些资源与依赖。 +- datavines-daemon.sh:容器内启动入口脚本,负责设置日志、JVM参数、类路径与执行主类。 + +章节来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L1-L150) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +## 架构总览 +下图展示从Dockerfile到容器运行的整体流程,以及环境变量对配置的影响。 + +```mermaid +sequenceDiagram +participant Dev as "开发者" +participant Docker as "Docker构建器" +participant Image as "DataVines镜像" +participant Compose as "Compose编排" +participant Container as "容器实例" +participant App as "DataVines服务" +Dev->>Docker : 触发构建指定版本ARG +Docker->>Docker : 基于openjdk : 8
安装tini
复制打包产物
解压并修正权限 +Docker-->>Image : 产出镜像含启动脚本与二进制包 +Dev->>Compose : 指定镜像与.env +Compose->>Container : 创建容器端口映射、网络、重启策略 +Container->>App : 以tini为init进程启动 +App->>App : 读取application.yaml与.env
加载Spring Profile与数据库配置 +App-->>Dev : 对外提供服务默认端口5600 +``` + +图表来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +## 详细组件分析 + +### Dockerfile逐层解析 +- 基础镜像与维护者信息:使用openjdk:8作为基础镜像,便于Java应用运行。 +- 版本参数与环境变量:通过ARG传入版本号,默认1.0.0-SNAPSHOT;设置时区与语言,确保日志与字符集一致。 +- 工作目录与tini:创建工作目录/opt,安装tini作为init进程,保证信号处理与僵尸进程清理。 +- 复制与解压:复制打包产物至镜像根目录并解压,重命名为datavines,删除压缩包。 +- 权限修正:赋予启动脚本可执行权限并清理回车符,避免容器内换行问题。 +- 端口暴露与启动命令:暴露5600端口;使用tini作为PID1,调用启动脚本以start_container模式运行。 + +章节来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) + +### 启动脚本与运行模式 +- 脚本职责:设置日志配置、JVM参数、类路径、主类;支持start、start_container、start_with_jmx、stop、status等模式。 +- 容器模式:start_container模式在容器内直接前台运行,适合由容器管理器(如Docker或Compose)接管生命周期。 +- 日志与JMX:默认使用server-logback.xml进行日志输出;可选启用JMX监控(通过start_with_jmx)。 + +章节来源 +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +### 配置覆盖机制(application.yaml与环境变量) +- Spring Profile:通过环境变量切换数据库类型(例如mysql),对应application.yaml中的多配置文件激活。 +- 数据库连接:通过环境变量覆盖driver-class-name、url、username、password等,实现不同数据库的快速切换。 +- 服务端口:application.yaml中server.port默认5600,可通过环境变量覆盖(如DOCKER_HOST_PORT映射外部端口)。 +- 其他配置:management、logging等也可通过环境变量或配置文件覆盖,遵循Spring Boot的配置优先级规则。 + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [.env](file://deploy/compose/.env#L1-L5) + +### 打包产物与装配清单 +- 装配清单:datavines-bin.xml定义了打包格式、输出目录、资源文件与依赖集合,确保最终二进制包包含运行所需的配置、脚本与插件依赖。 +- 依赖范围:包含Spark/Flink引擎插件、常用JDBC驱动等,满足多数据源场景。 + +章节来源 +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L1-L150) + +## 依赖关系分析 +- Dockerfile依赖打包产物(datavines-dist/target/datavines-${VERSION}-bin.tar.gz)与启动脚本(bin/datavines-daemon.sh)。 +- 容器运行依赖application.yaml与.env中的配置,其中.env通过环境变量覆盖application.yaml的关键项。 +- Compose编排依赖镜像与网络配置,确保容器间通信与端口可达。 + +```mermaid +graph LR +BINXML["datavines-bin.xml"] --> TAR["打包产物
datavines-${VERSION}-bin.tar.gz"] +TAR --> DF["Dockerfile"] +DAEMON["datavines-daemon.sh"] --> DF +APPYML["application.yaml"] --> DAEMON +ENV[".env"] --> APPYML +DC["docker-compose.yaml"] --> ENV +DC --> DF +``` + +图表来源 +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L1-L150) +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [.env](file://deploy/compose/.env#L1-L5) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) + +章节来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L1-L150) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +## 性能与资源考虑 +- JVM内存与GC:启动脚本设置了较大的堆与G1GC参数,建议根据宿主机资源与业务负载调整-Xmx等参数。 +- 进程模型:使用tini作为init进程,有助于正确处理信号与子进程回收,提升容器稳定性。 +- 端口与网络:默认暴露5600,Compose中已做端口映射;若需高可用或集群部署,建议结合外部负载均衡与健康检查。 +- 插件与依赖:装配清单包含多种JDBC驱动与引擎插件,按需裁剪可减少镜像体积与启动时间。 + +章节来源 +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) + +## 故障排查指南 +- 容器无法启动或立即退出 + - 检查启动脚本是否以start_container模式运行,确认日志输出位置与权限。 + - 使用docker logs查看容器标准输出与错误日志。 +- 端口冲突或不可访问 + - 确认宿主机端口映射与容器内server.port一致;检查防火墙与安全组。 +- 数据库连接失败 + - 确认.env中数据库URL、用户名、密码与驱动类名正确;若使用MySQL,请激活mysql profile。 +- 配置未生效 + - 确认环境变量键名符合Spring Boot约定(如SPRING_DATASOURCE_URL);检查application.yaml与.env的优先级顺序。 + +章节来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +## 结论 +通过仓库提供的Dockerfile与Compose编排,可以快速构建并运行DataVines服务。关键在于理解Dockerfile的构建步骤、启动脚本的运行模式,以及如何利用环境变量覆盖application.yaml中的配置。结合合理的网络与资源规划,可在生产环境中稳定部署。 + +## 附录:构建与运行最佳实践 + +### 构建镜像 +- 使用ARG传递版本号,确保产物与镜像一致 +- 在构建前确保打包产物存在(datavines-dist/target/datavines-${VERSION}-bin.tar.gz) +- 构建命令示例(请替换为实际路径与版本): + - docker build -f deploy/docker/Dockerfile -t datavines:dev --build-arg VERSION=1.0.0-SNAPSHOT . + +章节来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L1-L150) + +### 运行容器 +- 使用Compose编排(推荐) + - docker-compose -f deploy/compose/docker-compose.yaml up -d + - 访问地址:http://localhost:5600 +- 单容器运行(不推荐用于生产) + - docker run -d --name datavines -p 5600:5600 --env-file deploy/compose/.env datavines:dev + +章节来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) + +### 环境变量覆盖要点 +- 切换数据库类型:SPRING_PROFILES_ACTIVE=mysql +- 数据库连接:SPRING_DATASOURCE_URL、SPRING_DATASOURCE_USERNAME、SPRING_DATASOURCE_PASSWORD、SPRING_DATASOURCE_DRIVER-CLASS_NAME +- 服务端口:可通过宿主机端口映射覆盖容器内server.port + +章节来源 +- [.env](file://deploy/compose/.env#L1-L5) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) + +### 数据卷挂载建议 +- 配置目录:挂载conf目录以持久化application.yaml与日志配置 +- 日志目录:挂载logs目录以便收集容器日志 +- 示例(Compose中可参考): + - volumes: + - ./conf:/opt/datavines/conf + - ./logs:/opt/datavines/logs + +章节来源 +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +### 网络与安全配置 +- 网络:使用自定义bridge网络,明确子网段,便于容器间通信 +- 安全:避免使用privileged=true(除非必要);限制容器能力与只读根文件系统 +- 重启策略:使用unless-stopped,配合健康检查可进一步增强可用性 + +章节来源 +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) + +### 镜像优化与安全建议 +- 层叠优化:合并apt-get更新与安装命令,清理缓存与临时文件 +- 最小化基础镜像:可考虑使用更小的基础镜像(如alpine-openjdk),但需验证兼容性 +- 多阶段构建:将构建产物与运行时分离,减小最终镜像体积 +- 安全扫描:定期对镜像进行漏洞扫描,及时更新基础镜像与依赖 +- 运行时安全:非root用户运行、禁用不必要的特权、最小权限原则 + +章节来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/Kubernetes\351\203\250\347\275\262.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/Kubernetes\351\203\250\347\275\262.md" new file mode 100644 index 00000000..31ef3551 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/Kubernetes\351\203\250\347\275\262.md" @@ -0,0 +1,323 @@ +# Kubernetes部署 + + +**本文引用的文件** +- [datavines.yaml](file://deploy/k8s/datavines.yaml) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [Dockerfile](file://deploy/docker/Dockerfile) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [OSUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/OSUtils.java) +- [NetUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/NetUtils.java) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/CommonPropertyUtils.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本指南面向运维与平台工程团队,系统性讲解如何在Kubernetes集群中部署DataVines。内容覆盖: +- 部署清单解析:Deployment、Service、Ingress等资源定义 +- 配置管理:通过ConfigMap管理application.yaml,通过Secret管理敏感信息 +- Pod配置:资源请求与限制、就绪与存活探针 +- 存储与持久化:建议方案与最佳实践 +- 服务暴露:NodePort、LoadBalancer、Ingress三种方式对比与配置 +- 水平扩展:副本数、滚动升级策略与扩缩容策略 +- 生产高可用:多副本、健康检查、存储与网络隔离、安全加固 + +## 项目结构 +DataVines的Kubernetes部署主要由以下文件支撑: +- K8s部署清单:deploy/k8s/datavines.yaml +- 应用配置模板:datavines-server/src/main/resources/application.yaml +- 容器镜像构建:deploy/docker/Dockerfile +- 数据库初始化脚本:scripts/sql/datavines-mysql.sql +- 运行时环境判断与网络工具:datavines-common/utils下的OSUtils、NetUtils、CommonPropertyUtils + +```mermaid +graph TB +subgraph "Kubernetes部署" +A["datavines.yaml
Deployment/Service/Ingress"] +B["application.yaml
应用配置模板"] +C["Dockerfile
容器镜像构建"] +D["datavines-mysql.sql
数据库初始化"] +end +subgraph "运行时工具" +E["OSUtils.java
K8s模式与资源评估"] +F["NetUtils.java
主机名与网络优先级"] +G["CommonPropertyUtils.java
端口与阈值常量"] +end +A --> B +A --> C +A --> D +A --> E +A --> F +A --> G +``` + +图表来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L112) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L200) +- [OSUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/OSUtils.java#L80-L166) +- [NetUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/NetUtils.java#L28-L110) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/CommonPropertyUtils.java#L34-L61) + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L112) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L200) +- [OSUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/OSUtils.java#L80-L166) +- [NetUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/NetUtils.java#L28-L110) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/CommonPropertyUtils.java#L34-L61) + +## 核心组件 +- Deployment:定义Pod模板、副本数、滚动更新策略,以及容器启动命令与环境变量 +- Service:暴露应用端口,支持ClusterIP、NodePort或LoadBalancer +- Ingress:对外提供域名访问,需配合Ingress Controller +- ConfigMap:用于挂载application.yaml配置文件 +- Secret:用于存放数据库密码等敏感信息 +- Pod安全与资源:容器特权、资源请求与限制、探针 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L112) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) + +## 架构总览 +DataVines在K8s中的典型拓扑如下: +- 外部流量经Ingress进入Service,再转发到后端Pod +- Pod内运行Java应用,监听5600端口 +- 应用通过环境变量连接数据库(默认MySQL) +- 配置通过ConfigMap挂载application.yaml,敏感信息通过Secret注入 + +```mermaid +graph TB +Client["客户端/浏览器"] --> Ingress["Ingress
域名 www.datavines.com"] +Ingress --> Service["Service
ClusterIP:5600"] +Service --> Pod["Pod
容器: datavines"] +Pod --> App["应用进程
端口 5600"] +App --> DB["数据库
MySQL/PostgreSQL"] +``` + +图表来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L63-L111) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L69-L96) + +## 详细组件分析 + +### Deployment:Pod与容器配置 +- 副本数与滚动更新:当前副本数为1,滚动更新策略为各25% surge/unavailable +- 启动命令与参数:通过daemon脚本启动容器,容器镜像来自私有仓库 +- 环境变量:激活profile为mysql,数据库URL、用户名、密码均以环境变量形式注入 +- 安全上下文:允许提权与特权模式,需结合最小权限原则审慎使用 +- 资源:当前未设置requests/limits,建议按生产环境配置 + +```mermaid +flowchart TD +Start(["创建Deployment"]) --> SetReplicas["设置replicas=1"] +SetReplicas --> RollingUpdate["滚动更新策略
maxSurge=25%
maxUnavailable=25%"] +RollingUpdate --> Container["容器配置
命令/参数/镜像/环境变量"] +Container --> Security["安全上下文
允许提权/特权"] +Security --> Resources["资源请求与限制
建议补充"] +Resources --> Ready["就绪/存活探针
建议补充"] +Ready --> End(["完成"]) +``` + +图表来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L61) + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L61) + +### Service:服务暴露 +- 类型:ClusterIP,仅集群内部可访问 +- 端口:5600,目标端口5600 +- 选择器:匹配Deployment标签 + +如需外部访问,可改为NodePort或LoadBalancer;若需域名访问,建议配合Ingress。 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L63-L87) + +### Ingress:域名访问 +- 入口类:datavines +- 规则:host为www.datavines.com,路径前缀“/”,转发至Service:5600 +- 注意:Ingress规则中的backend字段已过时,应使用标准backend引用 + +```mermaid +sequenceDiagram +participant U as "用户" +participant IG as "Ingress" +participant SVC as "Service" +participant POD as "Pod" +U->>IG : 访问 https : //www.datavines.com/ +IG->>SVC : 转发到 Service : 5600 +SVC->>POD : 转发到 Pod : 5600 +POD-->>U : 返回响应 +``` + +图表来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L88-L111) + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L88-L111) + +### ConfigMap:管理application.yaml +- 方案:将application.yaml打包为ConfigMap,挂载到容器指定路径 +- 优点:便于版本化管理、热更新(滚动重启生效)、与Secret解耦 +- 建议:将数据库连接、日志级别、端口等非敏感配置放入ConfigMap + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) + +### Secret:管理敏感信息 +- 方案:将数据库密码等敏感信息放入Secret,以环境变量或挂载文件形式注入 +- 最佳实践:最小权限、定期轮换、避免明文存储 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L37-L46) + +### Pod配置与探针 +- 端口:容器暴露5600,应用server.port=5600 +- 就绪探针:建议以HTTP GET /actuator/health/readiness或应用自检接口 +- 存活探针:建议以HTTP GET /actuator/health/liveness或应用自检接口 +- 探针参数:initialDelaySeconds、periodSeconds、timeoutSeconds、failureThreshold、successThreshold + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L69-L96) +- [Dockerfile](file://deploy/docker/Dockerfile#L40-L44) + +### 资源请求与限制 +- 当前清单未设置resources,建议为生产环境配置requests/limits +- 参考依据:应用端口与运行时工具对CPU/内存的评估逻辑 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L49-L50) +- [OSUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/OSUtils.java#L80-L166) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/CommonPropertyUtils.java#L34-L61) + +### 持久化存储 +- 当前清单未包含持久卷声明(PVC),应用数据默认写入容器本地磁盘 +- 建议:为数据库与应用日志目录配置PVC,确保数据持久化与高可用 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L112) + +### 服务暴露方式 +- ClusterIP:仅集群内访问(当前默认) +- NodePort:在所有节点开放固定端口,便于外网直连 +- LoadBalancer:由云厂商负载均衡器分配公网IP +- Ingress:统一入口,支持TLS、路由与限流 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L63-L87) + +### 水平扩展策略 +- 副本数:当前为1,建议根据业务量提升至2+副本 +- 滚动更新:maxSurge/maxUnavailable已配置,建议结合探针与资源限制优化 +- 扩缩容:HPA可根据CPU/内存或自定义指标自动扩缩 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L13-L23) + +## 依赖关系分析 +- 镜像与容器:Dockerfile定义了基础镜像、工作目录、暴露端口与启动命令 +- 配置与运行:application.yaml定义了数据库驱动、端口、Quartz集群模式等 +- 运行时网络:NetUtils在K8s模式下对主机名进行处理,OSUtils与CommonPropertyUtils提供资源评估与端口常量 + +```mermaid +graph LR +DF["Dockerfile"] --> IMG["容器镜像"] +IMG --> POD["Pod"] +CFG["application.yaml"] --> APP["应用进程"] +NET["NetUtils.java"] --> APP +OSU["OSUtils.java"] --> APP +CPU["CommonPropertyUtils.java"] --> APP +``` + +图表来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [NetUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/NetUtils.java#L28-L110) +- [OSUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/OSUtils.java#L80-L166) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/CommonPropertyUtils.java#L34-L61) + +章节来源 +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [NetUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/NetUtils.java#L28-L110) +- [OSUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/OSUtils.java#L80-L166) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/CommonPropertyUtils.java#L34-L61) + +## 性能考量 +- 端口与线程:应用端口为5600;运行时工具提供最大CPU负载与保留内存阈值,可用于资源评估 +- 资源规划:结合OSUtils与CommonPropertyUtils的阈值,合理设置requests/limits +- 数据库:Quartz集群模式与连接池参数影响并发与稳定性 +- 日志:建议将日志输出到标准输出,便于K8s采集 + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L69-L96) +- [OSUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/OSUtils.java#L80-L166) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/it/datavines/common/utils/CommonPropertyUtils.java#L34-L61) + +## 故障排查指南 +- 健康检查失败 + - 检查就绪/存活探针是否指向正确路径与端口 + - 查看Pod事件与日志,确认端口占用与权限问题 +- 数据库连接异常 + - 确认环境变量中的数据库URL、用户名、密码是否正确 + - 检查数据库可达性与初始化脚本执行情况 +- 配置不生效 + - 确认ConfigMap挂载路径与文件名一致 + - 确认Profile激活与配置项覆盖关系 +- Ingress无法访问 + - 确认Ingress Controller已部署且IngressClassName正确 + - 检查域名解析与证书配置 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L37-L46) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L200) + +## 结论 +- 当前清单提供了基础的K8s部署骨架,适合开发与测试环境 +- 生产环境建议补齐:探针、资源限制、持久化、Secret、Ingress TLS与灰度策略 +- 通过ConfigMap与Secret实现配置与密钥分离,遵循最小权限原则 +- 结合HPA与多副本,提升可用性与弹性 + +## 附录 + +### 部署清单要点对照 +- Deployment + - 副本数:当前1,建议≥2 + - 滚动更新:maxSurge/maxUnavailable已配置 + - 安全上下文:允许提权/特权,建议关闭 + - 资源:建议添加requests/limits +- Service + - 类型:ClusterIP,建议配合NodePort/LoadBalancer或Ingress +- Ingress + - host与路径:www.datavines.com与“/” + - backend字段:建议使用标准引用 +- ConfigMap + - 挂载application.yaml,非敏感配置 +- Secret + - 注入数据库密码等敏感信息 + +章节来源 +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L112) + +### 数据库初始化 +- 使用datavines-mysql.sql初始化数据库表结构与Quartz相关表 +- 确保数据库服务可达且初始化成功 + +章节来源 +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L200) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/\346\234\254\345\234\260\351\203\250\347\275\262.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/\346\234\254\345\234\260\351\203\250\347\275\262.md" new file mode 100644 index 00000000..04fc3843 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/\346\234\254\345\234\260\351\203\250\347\275\262.md" @@ -0,0 +1,285 @@ +# 本地部署 + + +**本文引用的文件列表** +- [pom.xml](file://pom.xml) +- [mvnw](file://mvnw) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [jmx_exporter_config.yaml](file://datavines-server/src/main/resources/jmx/jmx_exporter_config.yaml) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) +- [datavines-submit.sh](file://bin/datavines-submit.sh) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml) +- [README.md](file://README.md) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能与调优建议](#性能与调优建议) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本指南面向开发者与测试人员,提供DataVines在单机环境下的完整本地部署流程,涵盖从源码编译、依赖准备、数据库初始化、配置文件修改、服务启动与停止、以及常用运维操作与验证方法。文档同时给出JVM参数、端口、日志目录等关键配置项的说明,并对datavines-daemon.sh与datavines-submit.sh两个脚本的使用进行详解,帮助快速搭建可验证功能的本地环境。 + +## 项目结构 +DataVines采用多模块Maven工程组织,核心模块包括服务端、引擎、连接器、指标、通知、注册中心、UI等。打包产物通过datavines-dist模块生成发布包,包含bin脚本、conf配置、libs依赖与插件目录。 + +```mermaid +graph TB +A["根工程
pom.xml"] --> B["datavines-server
服务端"] +A --> C["datavines-dist
打包分发"] +A --> D["datavines-engine
执行引擎"] +A --> E["datavines-connector
数据源连接器"] +A --> F["datavines-metric
规则与指标"] +A --> G["datavines-notification
通知模块"] +A --> H["datavines-registry
注册中心"] +A --> I["datavines-ui
前端"] +C --> J["datavines-bin.xml
打包装配"] +J --> K["bin 脚本"] +J --> L["conf 配置"] +J --> M["libs 依赖"] +J --> N["plugins 引擎插件"] +``` + +图表来源 +- [pom.xml](file://pom.xml#L30-L45) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L21-L149) + +章节来源 +- [pom.xml](file://pom.xml#L30-L45) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L21-L149) + +## 核心组件 +- 服务端(datavines-server):Spring Boot应用,提供REST API、调度、元数据与规则执行入口。 +- 打包分发(datavines-dist):生成发布包,包含bin脚本、conf配置、libs与plugins。 +- 数据库初始化脚本(scripts/sql/datavines-mysql.sql):包含Quartz表与业务表结构及初始数据。 +- 启动脚本(bin/datavines-daemon.sh、bin/datavines-submit.sh):封装服务启动、停止、JMX监控与离线作业提交。 +- 配置文件(application.yaml):包含数据库连接、Quartz、端口、日志等关键配置;支持多Profile切换。 + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) +- [datavines-submit.sh](file://bin/datavines-submit.sh#L1-L49) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L160) + +## 架构总览 +下图展示本地单机部署的关键交互:客户端通过HTTP访问服务端;服务端使用Hikari连接池访问数据库;Quartz用于任务调度;JMX exporter可选开启;离线作业通过datavines-submit.sh提交。 + +```mermaid +graph TB +subgraph "本地主机" +U["浏览器/CLI 客户端"] +S["DataVines Server
application.yaml"] +DB["数据库
PostgreSQL 或 MySQL"] +QZ["Quartz 调度"] +JMX["JMX Exporter
jmx_exporter_config.yaml"] +BIN["bin 脚本
datavines-daemon.sh / datavines-submit.sh"] +end +U --> S +S --> DB +S --> QZ +S -. 可选 .-> JMX +BIN --> S +BIN --> DB +``` + +图表来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [jmx_exporter_config.yaml](file://datavines-server/src/main/resources/jmx/jmx_exporter_config.yaml#L1-L15) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L70-L133) +- [datavines-submit.sh](file://bin/datavines-submit.sh#L31-L49) + +## 详细组件分析 + +### 一、源码编译与打包 +- 使用Maven Wrapper(mvnw)或系统Maven进行编译打包,推荐使用官方提供的release构建方式以确保依赖一致。 +- 打包产物由datavines-dist模块生成,包含bin脚本、conf配置、libs依赖与引擎插件目录。 + +章节来源 +- [README.md](file://README.md#L29-L34) +- [mvnw](file://mvnw#L1-L317) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L21-L149) + +### 二、数据库初始化 +- 使用脚本初始化数据库表结构与基础数据。该脚本包含Quartz相关表与业务表(如用户、工作空间、配置、规则作业等),并包含默认用户与工作空间初始化记录。 +- 若使用MySQL作为数据源,请在application.yaml中激活mysql Profile;若使用PostgreSQL则保持默认Profile。 + +章节来源 +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L160) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L836-L893) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L84-L96) + +### 三、配置文件修改(application.yaml) +- 数据源配置 + - PostgreSQL默认配置:驱动、URL、账号、密码、连接池参数等。 + - MySQL Profile配置:通过spring.profiles.active=mysql切换,使用MySQL驱动与URL。 +- Quartz配置 + - job-store-type、initialize-schema、线程池大小、集群模式、表前缀、驱动委托类等。 +- 服务端口 + - server.port 默认5600。 +- 日志配置 + - logging.config 指向server-logback.xml。 +- 管理端点 + - management暴露所有端点,便于健康检查与指标采集。 + +章节来源 +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) + +### 四、datavines-daemon.sh 使用说明 +- 功能 + - 启动/停止/重启服务,支持容器内运行与JMX监控模式。 + - 支持Profile切换(如mysql)。 +- 关键行为 + - 设置DATAVINES_OPTS(JVM参数)、DATAVINES_PID_DIR、DATAVINES_LOG_DIR、DATAVINES_CONF_DIR、DATAVINES_LIB_JARS。 + - start/start_container/start_with_jmx分别对应后台启动、前台启动、带JMX启动。 + - stop会优雅关闭,超时未退出则强制kill。 + - status检查PID文件是否存在。 +- 常用命令 + - 启动(默认Profile):bin/datavines-daemon.sh start + - 启动(mysql Profile):bin/datavines-daemon.sh start mysql + - 带JMX启动:bin/datavines-daemon.sh start_with_jmx + - 停止:bin/datavines-daemon.sh stop + - 状态:bin/datavines-daemon.sh status + - 重启(带JMX):bin/datavines-daemon.sh restart_with_jmx + +章节来源 +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +### 五、datavines-submit.sh 使用说明 +- 功能 + - 提交离线作业(非Web调度),通过JobExecuteBootstrap执行。 +- 关键行为 + - 读取作业JSON文件路径,设置DATAVINES_OPTS与CLASSPATH,调用JobExecuteBootstrap。 +- 常用命令 + - 提交作业:bin/datavines-submit.sh /path/to/job.json + +章节来源 +- [datavines-submit.sh](file://bin/datavines-submit.sh#L1-L49) + +### 六、JVM参数、端口与日志目录 +- JVM参数(DATAVINES_OPTS) + - 默认包含堆内存、GC策略等参数,可根据机器资源调整。 +- 端口(server.port) + - 默认5600,可通过application.yaml修改。 +- 日志目录(DATAVINES_LOG_DIR) + - 默认logs目录,可在脚本中设置或通过环境变量覆盖。 +- JMX导出(可选) + - start_with_jmx模式启用JMX exporter,配置文件位于conf/jmx。 + +章节来源 +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L55-L61) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L69-L83) +- [jmx_exporter_config.yaml](file://datavines-server/src/main/resources/jmx/jmx_exporter_config.yaml#L1-L15) + +### 七、服务启动、停止、重启与验证 +- 启动 + - 使用datavines-daemon.sh start或start mysql(按需选择Profile)。 +- 停止 + - 使用datavines-daemon.sh stop,若进程未优雅退出则强制kill。 +- 重启 + - 使用datavines-daemon.sh restart_with_jmx(带JMX)或先stop再start。 +- 验证 + - 访问服务端口(默认5600)确认服务可用。 + - 查看日志文件(logs/datavines-server-*.out)定位问题。 + - 使用status检查进程PID。 + +章节来源 +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L70-L173) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L69-L71) + +## 依赖分析 +- 构建与打包 + - Maven Wrapper(mvnw)统一构建入口。 + - datavines-bin.xml定义了conf、libs、plugins的产出布局。 +- 运行时依赖 + - 服务端默认使用PostgreSQL;通过mysql Profile可切换至MySQL。 + - Quartz使用JDBC JobStore,需确保数据库表初始化完成。 +- 插件与引擎 + - plugins/spark与plugins/flink目录包含引擎相关依赖,便于扩展不同执行引擎。 + +```mermaid +graph LR +MVN["mvnw"] --> PKG["datavines-dist 打包"] +PKG --> CONF["conf 配置"] +PKG --> LIBS["libs 依赖"] +PKG --> PLUG["plugins 引擎插件"] +CONF --> APP["application.yaml"] +LIBS --> SRV["datavines-server"] +SRV --> DB["数据库"] +SRV --> QZ["Quartz"] +``` + +图表来源 +- [mvnw](file://mvnw#L1-L317) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L21-L149) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) + +章节来源 +- [mvnw](file://mvnw#L1-L317) +- [datavines-bin.xml](file://datavines-dist/src/main/assembly/datavines-bin.xml#L21-L149) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) + +## 性能与调优建议 +- JVM参数 + - 根据机器内存调整DATAVINES_OPTS中的堆大小与GC策略,默认已启用G1GC,可根据负载适当增大堆或调整Region大小。 +- 数据库连接池 + - application.yaml中Hikari连接池参数(最大连接数、空闲超时、连接超时等)可根据并发与延迟需求优化。 +- Quartz线程池 + - 线程池大小与批处理数量影响任务并发度,可根据规则数量与执行频率调整。 +- 日志与监控 + - 开启JMX监控可辅助观察运行指标;生产环境建议结合Prometheus/Grafana进行监控。 + +章节来源 +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L55-L61) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L23-L40) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L39-L60) + +## 故障排查指南 +- 无法启动服务 + - 检查端口占用与防火墙;确认application.yaml中数据库连接正确;查看logs日志文件。 +- 数据库初始化失败 + - 确认数据库已创建且用户具备权限;执行datavines-mysql.sql;若使用MySQL需激活mysql Profile。 +- 作业提交失败 + - 确认datavines-submit.sh传入的作业文件路径有效;检查libs目录下依赖是否齐全。 +- 服务停止不掉 + - 使用stop后仍存在进程,脚本会尝试强制kill,可手动清理PID文件后重试。 + +章节来源 +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L135-L153) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L836-L893) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [datavines-submit.sh](file://bin/datavines-submit.sh#L31-L49) + +## 结论 +通过本指南,您可以在单机环境下完成DataVines的源码编译、数据库初始化、配置修改与服务启动。配合datavines-daemon.sh与datavines-submit.sh,可实现服务的日常运维与离线作业提交。建议在生产环境中进一步完善监控、备份与高可用策略。 + +## 附录 +- 快速命令清单 + - 编译打包:mvnw clean package -Prelease -DskipTests + - 初始化数据库:执行scripts/sql/datavines-mysql.sql + - 启动服务(PostgreSQL):bin/datavines-daemon.sh start + - 启动服务(MySQL):bin/datavines-daemon.sh start mysql + - 带JMX启动:bin/datavines-daemon.sh start_with_jmx + - 停止服务:bin/datavines-daemon.sh stop + - 重启服务:bin/datavines-daemon.sh restart_with_jmx + - 提交作业:bin/datavines-submit.sh /path/to/job.json +- 关键配置项 + - 数据库:driver-class-name、url、username、password、Hikari参数 + - Quartz:job-store-type、initialize-schema、线程池与表前缀 + - 服务端口:server.port + - 日志:logging.config + - 管理端点:management.endpoints.web.exposure.include + +章节来源 +- [README.md](file://README.md#L29-L34) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L160) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L70-L173) +- [datavines-submit.sh](file://bin/datavines-submit.sh#L31-L49) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/\351\203\250\347\275\262\346\214\207\345\215\227.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/\351\203\250\347\275\262\346\214\207\345\215\227.md" new file mode 100644 index 00000000..d5375275 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\346\214\207\345\215\227/\351\203\250\347\275\262\346\214\207\345\215\227.md" @@ -0,0 +1,594 @@ +# 部署指南 + + +**本文档中引用的文件** +- [README.md](file://README.md) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) +- [datavines-submit.sh](file://bin/datavines-submit.sh) +- [Dockerfile](file://deploy/docker/Dockerfile) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [.env](file://deploy/compose/.env) +- [datavines.yaml](file://deploy/k8s/datavines.yaml) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + + +## 目录 +1. [简介](#简介) +2. [环境依赖](#环境依赖) +3. [单机部署](#单机部署) +4. [Docker部署](#docker部署) +5. [Docker Compose部署](#docker-compose部署) +6. [Kubernetes部署](#kubernetes部署) +7. [配置文件详解](#配置文件详解) +8. [生产环境最佳实践](#生产环境最佳实践) +9. [资源需求与性能调优](#资源需求与性能调优) +10. [部署验证与健康检查](#部署验证与健康检查) +11. [监控与日志管理](#监控与日志管理) + +## 简介 + +DataVines 是一个轻量级、易部署的数据质量服务框架,支持多种部署模式,包括单机部署、Docker部署、Docker Compose部署和Kubernetes部署。本指南将详细介绍各种部署方式的完整步骤、优缺点、适用场景以及生产环境下的最佳实践。 + +DataVines 采用去中心化设计,Server节点支持水平扩展,具备自动容错能力,确保作业不丢失或重复执行。系统最小依赖仅为MySQL,便于快速启动和验证数据质量操作。 + +**Section sources** +- [README.md](file://README.md#L24-L92) + +## 环境依赖 + +在部署DataVines之前,请确保满足以下环境依赖: + +1. **Java运行环境**:JDK 8 +2. **数据库**:MySQL(推荐5.7及以上版本)或PostgreSQL +3. **构建工具**:Maven 3.6.1及以上版本 +4. **可选执行引擎**: + - 若数据量较小或仅用于功能验证,可使用JDBC引擎 + - 若基于Spark运行,需确保服务器已安装Spark + +部署前需执行Maven打包命令生成可部署文件: +```bash +mvn clean package -Prelease -DskipTests +``` + +**Section sources** +- [README.md](file://README.md#L93-L98) + +## 单机部署 + +### 部署步骤 + +1. **获取发布包** + 从Maven构建生成的`datavines-dist/target/`目录获取`datavines-{version}-bin.tar.gz`发布包。 + +2. **解压安装包** + ```bash + tar -zxvf datavines-{version}-bin.tar.gz -C /opt/ + ``` + +3. **初始化数据库** + 执行SQL脚本创建所需表结构: + ```bash + mysql -u root -p < scripts/sql/datavines-mysql.sql + ``` + +4. **修改配置文件** + 编辑`conf/application.yaml`,根据实际环境修改数据库连接信息。 + +5. **启动服务** + 使用启动脚本启动DataVines服务: + ```bash + bin/datavines-daemon.sh start mysql + ``` + +6. **验证服务** + 访问`http://:5600`,确认Web界面正常加载。 + +### 优缺点分析 + +**优点**: +- 部署简单,适合开发测试环境 +- 资源占用少,易于维护 +- 无需额外容器化基础设施 + +**缺点**: +- 缺乏高可用性 +- 不支持水平扩展 +- 单点故障风险 + +**适用场景**:开发测试、功能验证、小规模数据质量检查。 + +**Section sources** +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L19-L183) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L800) + +## Docker部署 + +### 部署步骤 + +1. **构建Docker镜像** + 使用项目提供的Dockerfile构建镜像: + ```bash + docker build -t datavines:dev . + ``` + +2. **运行容器** + 启动DataVines容器: + ```bash + docker run -d --name datavines \ + -p 5600:5600 \ + -e SPRING_PROFILES_ACTIVE=mysql \ + -e SPRING_DATASOURCE_URL=jdbc:mysql://:3306/datavines?useSSL=false&serverTimezone=GMT%2B8 \ + -e SPRING_DATASOURCE_USERNAME=root \ + -e SPRING_DATASOURCE_PASSWORD=123456 \ + datavines:dev + ``` + +3. **数据库初始化** + 在宿主机或独立MySQL容器中执行`datavines-mysql.sql`脚本。 + +### 镜像构建说明 + +Dockerfile基于OpenJDK 8基础镜像,关键配置包括: +- 工作目录设置为`/opt` +- 拷贝并解压发布包 +- 暴露端口5600 +- 使用tini作为init进程 +- 启动命令调用`datavines-daemon.sh start_container` + +### 优缺点分析 + +**优点**: +- 环境隔离,避免依赖冲突 +- 快速部署和迁移 +- 版本控制方便 + +**缺点**: +- 需要管理Docker环境 +- 单容器仍存在单点故障 +- 网络配置相对复杂 + +**适用场景**:需要环境隔离的测试环境、CI/CD流水线。 + +```mermaid +graph TD +A[Docker Host] --> B[Docker Engine] +B --> C[DataVines Container] +C --> D[Port 5600] +C --> E[Environment Variables] +E --> F[SPRING_PROFILES_ACTIVE] +E --> G[SPRING_DATASOURCE_*] +C --> H[datavines-daemon.sh] +H --> I[Start Service] +``` + +**Diagram sources** +- [Dockerfile](file://deploy/docker/Dockerfile#L1-L44) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L1-L183) + +## Docker Compose部署 + +### 部署步骤 + +1. **准备配置文件** + 确保`deploy/compose/`目录下存在`docker-compose.yaml`和`.env`文件。 + +2. **修改环境变量** + 编辑`.env`文件,配置数据库连接参数: + ``` + SPRING_PROFILES_ACTIVE=mysql + SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/datavines?... + SPRING_DATASOURCE_USERNAME=root + SPRING_DATASOURCE_PASSWORD=123456 + ``` + +3. **启动服务** + 使用Docker Compose启动服务: + ```bash + docker-compose -f deploy/compose/docker-compose.yaml up -d + ``` + +4. **初始化数据库** + 进入MySQL容器执行初始化脚本,或使用外部MySQL服务。 + +### 配置文件详解 + +`docker-compose.yaml`定义了单个服务: +- 镜像:`datavines:dev` +- 容器名称:`datavines` +- 端口映射:5600:5600 +- 环境变量文件:`.env` +- 重启策略:`unless-stopped` +- 自定义网络:`datavines`(子网172.18.0.0/24) + +### 优缺点分析 + +**优点**: +- 多容器编排,配置集中管理 +- 环境变量分离,安全性高 +- 支持服务依赖管理 +- 易于扩展为多服务架构 + +**缺点**: +- 需要Docker Compose工具 +- 网络配置复杂度增加 +- 调试相对困难 + +**适用场景**:需要多服务协同的测试环境、预生产环境。 + +```mermaid +graph LR +A[Docker Compose] --> B[datavines Service] +B --> C[Image: datavines:dev] +B --> D[Port: 5600:5600] +B --> E[Env File: .env] +B --> F[Network: datavines] +E --> G[Database Connection] +F --> H[Subnet: 172.18.0.0/24] +``` + +**Diagram sources** +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml#L1-L19) +- [.env](file://deploy/compose/.env#L1-L5) + +## Kubernetes部署 + +### 部署步骤 + +1. **准备部署文件** + 使用`deploy/k8s/datavines.yaml`作为部署模板。 + +2. **修改配置** + 根据实际环境调整以下参数: + - 命名空间(默认为`bigdata`) + - 镜像地址 + - 数据库连接信息 + - 资源限制 + - Ingress主机名 + +3. **应用部署** + ```bash + kubectl apply -f deploy/k8s/datavines.yaml + ``` + +4. **验证部署** + 检查Pod状态: + ```bash + kubectl get pods -n bigdata + ``` + +### 配置文件结构 + +`datavines.yaml`包含三个核心资源: + +1. **Deployment**: + - 副本数:1 + - 滚动更新策略 + - 容器配置:命令、参数、环境变量、资源 + - 安全上下文:特权模式 + +2. **Service**: + - 类型:ClusterIP + - 端口:5600 + - 选择器匹配Deployment标签 + +3. **Ingress**: + - 入口类:`datavines` + - 主机:`www.datavines.com` + - 路径:`/` 转发到Service端口5600 + +### 优缺点分析 + +**优点**: +- 高可用性,支持自动恢复 +- 水平扩展能力 +- 资源隔离和限制 +- 服务发现和负载均衡 +- 滚动更新和回滚 + +**缺点**: +- 基础设施复杂 +- 运维成本高 +- 学习曲线陡峭 + +**适用场景**:生产环境、需要高可用和弹性伸缩的场景。 + +```mermaid +graph TD +A[Kubernetes Cluster] --> B[Deployment] +B --> C[Replicas: 1] +B --> D[Rolling Update] +B --> E[Container] +E --> F[Image: registry.cn-shanghai.aliyuncs.com/luckydata/datavines:dev] +E --> G[Port: 5600] +E --> H[Env: SPRING_DATASOURCE_*] +A --> I[Service] +I --> J[Type: ClusterIP] +I --> K[Port: 5600] +A --> L[Ingress] +L --> M[Host: www.datavines.com] +L --> N[Path: /] +N --> I +B --> I +``` + +**Diagram sources** +- [datavines.yaml](file://deploy/k8s/datavines.yaml#L1-L112) + +## 配置文件详解 + +### application.yaml + +核心配置项包括: + +**Spring配置**: +- `spring.datasource`:数据库连接信息 +- `spring.quartz`:Quartz调度器配置,支持集群模式 +- `server.port`:服务端口,默认5600 + +**数据库连接池**(HikariCP): +- `maximum-pool-size`:最大连接数(默认50) +- `connection-timeout`:连接超时时间 +- `idle-timeout`:空闲超时时间 + +**Quartz集群配置**: +- `org.quartz.jobStore.isClustered=true`:启用集群模式 +- `org.quartz.scheduler.instanceId=AUTO`:实例ID自动生成 +- `org.quartz.jobStore.clusterCheckinInterval=5000`:集群检查间隔 + +### profiles配置 + +通过`spring.profiles.active`激活不同环境配置: +- 默认配置:使用PostgreSQL +- `mysql` profile:覆盖为MySQL配置 +- 可通过环境变量`SPRING_PROFILES_ACTIVE`指定 + +### 日志配置 + +`server-logback.xml`定义了三种日志输出: +1. **STDOUT**:控制台输出 +2. **JOB_LOG_FILE**:作业日志,按作业ID分离 +3. **SERVER_LOG_FILE**:服务日志,按小时滚动 + +日志文件存储在`logs/`目录下,保留168小时(7天)。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L17-L96) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L1-L85) + +## 生产环境最佳实践 + +### 高可用配置 + +1. **多节点部署**: + - 部署多个DataVines Server实例 + - 使用负载均衡器(如Nginx、HAProxy)分发请求 + - 配置会话保持(Session Affinity) + +2. **数据库高可用**: + - 使用MySQL主从复制或MHA + - 或使用PostgreSQL流复制 + - 配置连接池的故障转移 + +3. **Quartz集群模式**: + - 确保`org.quartz.jobStore.isClustered=true` + - 所有节点使用同一数据库 + - 实例ID自动生成避免冲突 + +### 负载均衡 + +1. **Nginx配置示例**: + ```nginx + upstream datavines { + server node1:5600; + server node2:5600; + server node3:5600; + } + + server { + listen 80; + location / { + proxy_pass http://datavines; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + } + ``` + +2. **健康检查**: + - 配置Nginx健康检查端点 + - 使用`/actuator/health`接口 + +### 故障转移 + +1. **自动故障检测**: + - Kubernetes中使用Liveness和Readiness探针 + - Docker Compose中使用`healthcheck` + +2. **数据持久化**: + - 数据库存储核心元数据 + - 作业日志持久化到独立存储 + - 配置文件使用ConfigMap(K8s)或外部存储 + +3. **备份策略**: + - 定期备份数据库 + - 备份配置文件和证书 + - 测试恢复流程 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L39-L59) +- [README.md](file://README.md#L85-L92) + +## 资源需求与性能调优 + +### 资源需求估算 + +| 组件 | 最小配置 | 推荐配置 | 生产配置 | +|------|---------|---------|---------| +| Server节点 | 2核4G | 4核8G | 8核16G | +| JVM堆内存 | 1G | 4G | 8-16G | +| 数据库 | 2核4G | 4核8G | 8核16G | +| 存储空间 | 50G | 100G | 500G+ | + +### JVM调优 + +`datavines-daemon.sh`中配置的JVM参数: +- `-Xmx16g -Xms1g`:堆内存大小 +- `-XX:+UseG1GC`:使用G1垃圾收集器 +- `-XX:G1HeapRegionSize=8M`:G1区域大小 + +建议生产环境调整: +```bash +-DATAVINES_OPTS="-server -Xmx8g -Xms8g -XX:+UseG1GC -XX:MaxGCPauseMillis=200" +``` + +### 执行引擎参数 + +**Spark引擎参数**: +- `numExecutors`:执行器数量 +- `executorCores`:每个执行器核心数 +- `executorMemory`:每个执行器内存 +- 可通过`spark.engine.parameter.*`配置项设置 + +**Flink引擎参数**: +- `jobManagerMemory`:JobManager内存 +- `taskManagerMemory`:TaskManager内存 +- `parallelism`:并行度 +- `yarnQueue`:YARN队列 + +### 性能监控指标 + +1. **JVM指标**: + - 堆内存使用率 + - GC频率和暂停时间 + - 线程数 + +2. **数据库指标**: + - 连接数 + - 查询响应时间 + - 锁等待 + +3. **应用指标**: + - QPS(每秒查询数) + - 作业执行时间 + - 错误率 + +**Section sources** +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L59-L60) +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L48-L68) +- [FlinkConfig UI](file://datavines-ui/Editor/components/FlinkConfig/index.tsx#L97-L121) + +## 部署验证与健康检查 + +### 验证步骤 + +1. **服务进程检查**: + ```bash + ps -ef | grep datavines + ``` + +2. **端口监听检查**: + ```bash + netstat -anp | grep 5600 + ``` + +3. **API健康检查**: + ```bash + curl http://localhost:5600/actuator/health + ``` + 预期返回:`{"status":"UP"}` + +4. **Web界面访问**: + - 访问`http://:5600` + - 验证登录页面正常加载 + +5. **数据库连接验证**: + - 检查日志中是否有数据库连接成功信息 + - 查询`dv_server`表确认节点注册 + +### 健康检查方法 + +1. **主动健康检查**: + - 定期调用`/actuator/health`接口 + - 检查响应状态码和内容 + +2. **日志监控**: + - 监控`logs/datavines-server.log` + - 关注ERROR和WARN级别日志 + +3. **指标监控**: + - 通过`/actuator/metrics`暴露的指标 + - 集成Prometheus和Grafana + +4. **作业执行测试**: + - 创建简单数据质量检查作业 + - 验证作业能正常提交和执行 + - 检查作业日志输出 + +**Section sources** +- [datavines-daemon.sh](file://bin/datavines-daemon.sh#L155-L165) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L61-L77) + +## 监控与日志管理 + +### 监控方案 + +1. **JMX监控**: + - 启用JMX导出器:`-javaagent:jmx_prometheus_javaagent.jar=10010:config.yaml` + - 通过`http://:10010/metrics`暴露指标 + - 集成Prometheus抓取 + +2. **Spring Boot Actuator**: + - `/actuator/health`:健康检查 + - `/actuator/metrics`:性能指标 + - `/actuator/info`:应用信息 + +3. **分布式追踪**: + - 集成Zipkin或Jaeger + - 跟踪作业执行链路 + +### 日志管理 + +1. **日志级别**: + - 生产环境:INFO + - 调试环境:DEBUG + - 可通过`logging.level.*`配置 + +2. **日志轮转**: + - 按小时和大小滚动(200MB) + - 保留7天历史日志 + - 配置在`server-logback.xml` + +3. **日志分离**: + - 服务日志:`datavines-server.log` + - 作业日志:按作业ID分离存储 + - 敏感信息过滤:通过`ServerLogFilter`实现 + +4. **集中日志**: + - 使用ELK(Elasticsearch, Logstash, Kibana)栈 + - 或EFK(Elasticsearch, Fluentd, Kibana) + - 配置Filebeat采集日志 + +### 告警配置 + +1. **阈值告警**: + - JVM内存使用率 > 80% + - GC暂停时间 > 1s + - 作业失败率 > 5% + +2. **通知渠道**: + - 邮件 + - 钉钉 + - 企业微信 + - 飞书 + +3. **SLA管理**: + - 配置检查结果告警SLA + - 设置通知发送者和接收者 + +**Section sources** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L21-L85) +- [ServerLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/ServerLogFilter.java#L1-L47) +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java#L30-L68) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\345\256\211\345\205\250\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\345\256\211\345\205\250\351\205\215\347\275\256.md" new file mode 100644 index 00000000..aad8744b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\345\256\211\345\205\250\351\205\215\347\275\256.md" @@ -0,0 +1,476 @@ +# 安全配置 + + +**本文档引用的文件** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [AccessTokenService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/AccessTokenService.java) +- [AccessTokenController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/AccessTokenController.java) +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [EMailSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) + + +## 目录 +1. [简介](#简介) +2. [用户认证机制](#用户认证机制) +3. [权限控制](#权限控制) +4. [敏感数据加密与保护](#敏感数据加密与保护) +5. [API访问控制](#api访问控制) +6. [安全参数配置](#安全参数配置) +7. [敏感信息安全管理](#敏感信息安全管理) +8. [网络安全措施](#网络安全措施) +9. [安全审计与日志记录](#安全审计与日志记录) +10. [部署安全建议](#部署安全建议) + +## 简介 +DataVines是一个数据质量监控平台,提供了全面的安全机制来保护系统和数据安全。本文档详细说明了DataVines的安全配置选项,包括用户认证、权限控制、敏感数据加密、API访问控制等核心安全功能。系统采用JWT(JSON Web Token)作为主要的用户认证机制,结合验证码、密码策略等多重安全措施,确保系统的安全性。同时,平台提供了敏感数据加密存储、日志脱敏、SQL注入防护等安全特性,为用户提供了一个安全可靠的数据质量管理环境。 + +## 用户认证机制 + +DataVines采用基于JWT的用户认证机制,通过TokenManager类实现Token的生成、验证和管理。系统支持多种认证方式,包括用户名密码认证和访问令牌认证。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AuthController as "认证控制器" +participant TokenManager as "Token管理器" +participant UserService as "用户服务" +Client->>AuthController : 提交用户名和密码 +AuthController->>UserService : 验证用户凭证 +UserService-->>AuthController : 返回用户信息 +AuthController->>TokenManager : 请求生成Token +TokenManager->>TokenManager : 创建包含用户信息的Claims +TokenManager-->>AuthController : 返回JWT Token +AuthController-->>Client : 返回Token和用户信息 +Client->>AuthController : 后续请求携带Token +AuthController->>TokenManager : 验证Token有效性 +TokenManager-->>AuthController : 返回验证结果 +AuthController->>UserService : 获取用户信息 +UserService-->>AuthController : 返回用户信息 +AuthController-->>Client : 返回请求结果 +``` + +**图示来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L42-L50) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L89-L98) + +## 权限控制 + +DataVines实现了基于注解的权限控制机制,通过AuthIgnore和CheckTokenExist注解来管理API接口的访问权限。系统采用拦截器模式,在请求处理前进行权限验证。 + +```mermaid +flowchart TD +Start([请求开始]) --> CheckAnnotation["检查方法注解"] +CheckAnnotation --> HasAuthIgnore{"存在@AuthIgnore?"} +HasAuthIgnore --> |是| AllowAccess["允许访问"] +HasAuthIgnore --> |否| ExtractToken["提取请求头中的Token"] +ExtractToken --> TokenExists{"Token存在?"} +TokenExists --> |否| ReturnError["返回Token为空错误"] +TokenExists --> |是| CheckTokenExist{"存在@CheckTokenExist?"} +CheckTokenExist --> |是| ValidateTokenInDB["验证Token存在于数据库"] +CheckTokenExist --> |否| ValidateToken["验证Token有效性"] +ValidateTokenInDB --> |无效| ReturnInvalidToken["返回无效Token错误"] +ValidateToken --> |无效| ReturnInvalidToken +ValidateTokenInDB --> |有效| GetUser["获取用户信息"] +ValidateToken --> |有效| GetUser +GetUser --> |用户不存在| ReturnInvalidToken +GetUser --> |用户存在| SetContext["设置上下文用户信息"] +SetContext --> AllowAccess +AllowAccess --> End([请求结束]) +ReturnError --> End +ReturnInvalidToken --> End +``` + +**图示来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L54-L104) +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) + +**本节来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L42-L116) +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) + +## 敏感数据加密与保护 + +DataVines提供了多层次的敏感数据保护机制,包括数据加密存储、日志脱敏和敏感参数过滤。 + +### 数据加密存储 +系统使用AES加密算法对敏感数据进行加密存储,确保即使数据库被非法访问,敏感信息也不会泄露。 + +```mermaid +classDiagram +class CryptionUtils { ++static String ALGORITHM ++static String TRANSFORMATION ++static String IV_PARAMETER_SPE ++encryptByAES(input String, key String) String ++decryptByAES(input String, key String) String ++hexStringToBytes(hexString String) byte[] ++bytesToHexString(sources byte[]) String +} +class PasswordFilterUtils { ++convertPassword(pwdPattern Pattern, msg String) String ++convertPasswordToNULL(pwdPattern Pattern, msg String) String ++passwordHandler(pwdPattern Pattern, logMsg String, convertToNull boolean) String +} +class SensitiveDataConverter { ++static String DATASOURCE_PASSWORD_REGEX ++static String DATASOURCE_PASSWORD_REGEX_1 ++static Pattern PWD_PATTERN ++static Pattern PWD_PATTERN_1 ++convert(event ILoggingEvent) String +} +class SensitiveLogUtils { ++maskDataSourcePwd(dataSourcePwd String) String +} +CryptionUtils --> PasswordFilterUtils : "使用" +PasswordFilterUtils --> SensitiveLogUtils : "使用" +SensitiveDataConverter --> PasswordFilterUtils : "使用" +``` + +**图示来源** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L27-L31) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L25-L76) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L34-L49) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java#L30-L35) + +### 日志脱敏 +系统通过Logback的自定义转换器实现日志脱敏,自动将日志中的密码等敏感信息替换为掩码。 + +```mermaid +flowchart TD +OriginalLog["原始日志消息"] --> SensitiveDataConverter["敏感数据转换器"] +SensitiveDataConverter --> ExtractMessage["提取格式化日志消息"] +ExtractMessage --> FindPassword["查找密码模式"] +FindPassword --> HasPassword{"找到密码?"} +HasPassword --> |是| ReplacePassword["替换为掩码"] +HasPassword --> |否| ReturnOriginal["返回原始消息"] +ReplacePassword --> ReturnMasked["返回脱敏消息"] +ReturnOriginal --> FinalLog["最终日志输出"] +ReturnMasked --> FinalLog +FinalLog --> LogFile["写入日志文件"] +``` + +**图示来源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L51-L58) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L33-L34) + +**本节来源** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L26-L84) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L25-L76) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L29-L60) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java#L24-L38) + +## API访问控制 + +DataVines通过Swagger集成和API网关模式实现API访问控制,确保只有授权用户才能访问特定的API接口。 + +```mermaid +graph TD +Client["API客户端"] --> SwaggerUI["Swagger UI"] +SwaggerUI --> Auth["认证"] +Auth --> |Bearer Token| APIGateway["API网关"] +APIGateway --> |验证Token| AuthenticationInterceptor["认证拦截器"] +AuthenticationInterceptor --> |验证通过| APIController["API控制器"] +APIController --> BusinessLogic["业务逻辑"] +BusinessLogic --> Response["返回结果"] +Response --> APIGateway +APIGateway --> Client +style SwaggerUI fill:#f9f,stroke:#333 +style APIGateway fill:#bbf,stroke:#333 +style AuthenticationInterceptor fill:#f96,stroke:#333 +``` + +**图示来源** +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java#L42-L50) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +**本节来源** +- [DataVinesSwaggerConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java#L19-L72) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L42-L116) + +## 安全参数配置 + +DataVines提供了丰富的安全参数配置选项,允许管理员根据安全需求进行定制化配置。 + +### 验证码配置 +系统支持图形验证码功能,通过Kaptcha库生成验证码图片,并使用JWT保护验证码的安全传输。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant VerificationUtil as "验证码工具" +participant Kaptcha as "Kaptcha" +participant TokenManager as "Token管理器" +Client->>VerificationUtil : 请求验证码 +VerificationUtil->>Kaptcha : 生成验证码文本 +Kaptcha-->>VerificationUtil : 返回验证码文本 +VerificationUtil->>Kaptcha : 生成验证码图片 +Kaptcha-->>VerificationUtil : 返回图片 +VerificationUtil->>TokenManager : 生成包含验证码的JWT +TokenManager-->>VerificationUtil : 返回JWT +VerificationUtil-->>Client : 返回图片和JWT +Client->>VerificationUtil : 提交验证码和JWT +VerificationUtil->>TokenManager : 解析JWT获取验证码 +TokenManager-->>VerificationUtil : 返回验证码 +VerificationUtil->>VerificationUtil : 比较验证码 +VerificationUtil-->>Client : 返回验证结果 +``` + +**图示来源** +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java#L52-L112) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java#L29-L36) + +### 会话超时配置 +系统通过JWT的过期时间机制实现会话超时控制,管理员可以在配置文件中设置Token的有效期。 + +```mermaid +flowchart TD +Login["用户登录"] --> GenerateToken["生成JWT Token"] +GenerateToken --> SetExpire["设置过期时间"] +SetExpire --> StoreToken["存储Token"] +StoreToken --> ReturnToken["返回Token给客户端"] +ClientRequest["客户端请求"] --> ExtractToken["提取Token"] +ExtractToken --> CheckExpire["检查Token是否过期"] +CheckExpire --> |未过期| ProcessRequest["处理请求"] +CheckExpire --> |已过期| ReturnError["返回过期错误"] +ProcessRequest --> UpdateToken["刷新Token"] +UpdateToken --> ReturnResponse["返回响应"] +``` + +**图示来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L45-L46) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java#L57-L58) + +**本节来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java#L29-L36) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java#L52-L112) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L42-L46) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L42-L46) + +## 敏感信息安全管理 + +DataVines提供了全面的敏感信息安全管理机制,确保数据库密码、API密钥等敏感信息的安全存储和管理。 + +### 访问令牌管理 +系统支持创建和管理访问令牌,允许用户为不同的应用场景创建具有特定有效期的访问令牌。 + +```mermaid +classDiagram +class AccessTokenService { ++checkTokenExist(token String) Boolean ++create(tokenCreate TokenCreate) Long ++update(tokenUpdate TokenUpdate) Long ++deleteToken(id Long) boolean ++page(workspaceId Long, userId Long, pageNumber Integer, pageSize Integer) IPage~AccessToken~ +} +class TokenCreate { ++workspaceId long ++expireTime String +} +class TokenUpdate { ++id Long ++workspaceId long ++expireTime String +} +class AccessTokenController { ++create(TokenCreate tokenCreate) Object ++update(TokenUpdate tokenUpdate) Object ++delete(Long id) Object ++listByUserId(workspaceId Long, pageNumber Integer, pageSize Integer) Object +} +AccessTokenService <|-- AccessTokenServiceImpl +AccessTokenController --> AccessTokenService : "依赖" +TokenCreate --> AccessTokenService : "作为参数" +TokenUpdate --> AccessTokenService : "作为参数" +``` + +**图示来源** +- [AccessTokenService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/AccessTokenService.java#L28-L39) +- [AccessTokenController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/AccessTokenController.java#L59-L68) + +### 数据库连接安全 +系统对数据库连接参数进行特殊处理,过滤可能的安全风险参数,如autoDeserialize等。 + +```mermaid +flowchart TD +InputParams["输入连接参数"] --> FilterProperties["过滤属性"] +FilterProperties --> CheckSensitive["检查敏感参数"] +CheckSensitive --> |包含autoDeserialize| LogWarning["记录警告日志"] +CheckSensitive --> |不包含| ProcessNormal["正常处理"] +LogWarning --> RemoveParam["移除敏感参数"] +RemoveParam --> ProcessNormal +ProcessNormal --> CreateConnection["创建数据库连接"] +CreateConnection --> ReturnConnection["返回连接"] +``` + +**图示来源** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java#L60-L74) + +**本节来源** +- [AccessTokenService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/AccessTokenService.java#L28-L39) +- [AccessTokenServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/AccessTokenServiceImpl.java#L116-L124) +- [AccessTokenController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/AccessTokenController.java#L59-L68) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java#L60-L74) + +## 网络安全措施 + +DataVines实施了多项网络安全措施,包括HTTPS配置、CSRF防护和SQL注入防护。 + +### HTTPS配置 +虽然代码库中未直接显示HTTPS配置,但系统通过标准的Spring Boot配置方式支持HTTPS。 + +```mermaid +flowchart TD +SSLConfig["SSL配置"] --> KeyStore["密钥库文件"] +SSLConfig --> TrustStore["信任库文件"] +SSLConfig --> Port["HTTPS端口"] +SSLConfig --> Protocol["协议版本"] +KeyStore --> |PKCS12或JKS| SSLConfig +TrustStore --> |CA证书| SSLConfig +Port --> |8443| SSLConfig +Protocol --> |TLSv1.2+| SSLConfig +SSLConfig --> ApplicationYaml["application.yaml"] +ApplicationYaml --> Server["Spring Boot服务器"] +Server --> Clients["客户端连接"] +``` + +**本节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +### SQL注入防护 +系统通过MyBatis Plus框架和参数化查询防止SQL注入攻击,同时对用户输入进行严格验证。 + +```mermaid +flowchart TD +UserInput["用户输入"] --> InputValidation["输入验证"] +InputValidation --> |有效| Parameterize["参数化查询"] +InputValidation --> |无效| RejectRequest["拒绝请求"] +Parameterize --> MyBatisPlus["MyBatis Plus"] +MyBatisPlus --> Database["数据库"] +Database --> |预编译语句| Execute["执行查询"] +Execute --> ReturnResult["返回结果"] +``` + +**本节来源** +- [mybatis-plus配置](file://datavines-server/src/main/resources/application.yaml#L64-L68) +- [输入验证逻辑](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) + +## 安全审计与日志记录 + +DataVines提供了完善的安全审计和日志记录功能,帮助管理员监控系统安全状态。 + +### 日志配置 +系统使用Logback作为日志框架,配置了详细的日志记录策略和敏感数据脱敏。 + +```mermaid +graph TD +LogbackConfig["Logback配置"] --> ConsoleAppender["控制台输出"] +LogbackConfig --> FileAppender["文件输出"] +LogbackConfig --> SensitiveConverter["敏感数据转换器"] +ConsoleAppender --> PatternLayout["格式化模式"] +FileAppender --> SiftingAppender["分流追加器"] +SiftingAppender --> JobLogDiscriminator["作业日志判别器"] +SiftingAppender --> JobLogFilter["作业日志过滤器"] +SensitiveConverter --> PasswordFilter["密码过滤"] +PasswordFilter --> MaskPassword["掩码密码"] +PatternLayout --> ConsoleOutput["控制台输出"] +SiftingAppender --> FileOutput["文件输出"] +MaskPassword --> FileOutput +``` + +**图示来源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L24-L59) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) + +### 安全审计 +系统记录所有关键操作的日志,包括用户登录、Token创建和删除等操作。 + +```mermaid +flowchart TD +SecurityEvent["安全事件"] --> EventType{"事件类型"} +EventType --> |用户登录| LoginAudit["登录审计"] +EventType --> |Token创建| TokenCreateAudit["Token创建审计"] +EventType --> |Token删除| TokenDeleteAudit["Token删除审计"] +EventType --> |配置修改| ConfigAudit["配置修改审计"] +LoginAudit --> LogDetails["记录用户、时间、IP"] +TokenCreateAudit --> LogDetails +TokenDeleteAudit --> LogDetails +ConfigAudit --> LogDetails +LogDetails --> LogStorage["日志存储"] +LogStorage --> LogFile["日志文件"] +LogStorage --> Database["数据库"] +``` + +**本节来源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L29-L60) +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java) + +## 部署安全建议 + +DataVines提供了多种部署方式,包括Docker Compose和Kubernetes,建议采取以下安全措施。 + +### Docker部署安全 +使用Docker Compose部署时,应遵循最小权限原则,避免使用privileged模式。 + +```mermaid +graph TD +DockerCompose["docker-compose.yaml"] --> Service["服务配置"] +Service --> Image["镜像"] +Service --> Ports["端口映射"] +Service --> EnvFile["环境变量文件"] +Service --> Networks["网络配置"] +Image --> |datavines:dev| Service +Ports --> |5600:5600| Service +EnvFile --> |.env| Service +Networks --> |datavines| Service +SecurityConcerns["安全注意事项"] --> AvoidPrivileged["避免privileged: true"] +SecurityConcerns --> SecureEnv["保护.env文件"] +SecurityConcerns --> NetworkIsolation["网络隔离"] +SecurityConcerns --> RegularUpdate["定期更新镜像"] +Service --> SecurityConcerns +``` + +**图示来源** +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) + +### 邮件通知安全 +系统支持通过邮件发送通知,配置时应使用安全的SMTP连接。 + +```mermaid +flowchart TD +EmailConfig["邮件配置"] --> SMTPHost["SMTP主机"] +EmailConfig --> SMTPPort["SMTP端口"] +EmailConfig --> EnableAuth["启用认证"] +EmailConfig --> EnableTLS["启用TLS"] +EmailConfig --> EnableSSL["启用SSL"] +EmailConfig --> SSLTrust["SSL信任"] +SMTPHost --> |mail.smtp.host| Properties["JavaMail属性"] +SMTPPort --> |mail.smtp.port| Properties +EnableAuth --> |mail.smtp.auth| Properties +EnableTLS --> |mail.smtp.starttls.enable| Properties +EnableSSL --> |mail.smtp.ssl.enable| Properties +SSLTrust --> |mail.smtp.ssl.trust| Properties +Properties --> EMailSender["EMailSender"] +EMailSender --> SendEmail["发送邮件"] +``` + +**图示来源** +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java#L116-L143) +- [EMailSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java#L158-L163) + +**本节来源** +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java#L108-L160) +- [EMailSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java#L154-L163) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256.md" new file mode 100644 index 00000000..d0559a62 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256.md" @@ -0,0 +1,368 @@ +# 授权配置 + + +**本文档引用的文件** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) +- [UserWorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/UserWorkSpace.java) +- [UserService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/UserService.java) +- [AccessTokenService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/AccessTokenService.java) +- [WorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/WorkSpaceServiceImpl.java) + + +## 目录 +1. [简介](#简介) +2. [权限控制架构](#权限控制架构) +3. [基于注解的访问控制](#基于注解的访问控制) +4. [API接口权限管理](#api接口权限管理) +5. [用户角色与工作空间权限模型](#用户角色与工作空间权限模型) +6. [AuthenticationInterceptor实现机制](#authenticationinterceptor实现机制) +7. [权限验证流程](#权限验证流程) +8. [用户、租户与工作空间权限关系](#用户租户与工作空间权限关系) +9. [配置示例](#配置示例) +10. [权限继承与性能优化](#权限继承与性能优化) +11. [常见授权问题解决方案](#常见授权问题解决方案) + +## 简介 +DataVines权限控制系统提供了一套完整的访问控制机制,包括基于注解的访问控制、API接口权限管理、用户角色和工作空间权限模型。系统通过AuthenticationInterceptor实现统一的权限验证流程,支持灵活的权限配置和管理。本文档详细说明了DataVines的权限控制机制,帮助用户理解和配置系统的授权功能。 + +## 权限控制架构 +DataVines的权限控制架构基于Spring MVC拦截器模式,通过AuthenticationInterceptor实现全局的权限验证。系统采用基于Token的认证机制,结合用户、工作空间和租户的多层级权限模型,实现了细粒度的访问控制。 + +```mermaid +graph TD +Client[客户端] --> API[API接口] +API --> Interceptor[AuthenticationInterceptor] +Interceptor --> TokenValidation[Token验证] +Interceptor --> PermissionCheck[权限检查] +TokenValidation --> UserService[UserService] +TokenValidation --> AccessTokenService[AccessTokenService] +PermissionCheck --> UserWorkSpace[用户工作空间关系] +PermissionCheck --> Role[角色权限] +UserService --> Database[(数据库)] +AccessTokenService --> Database +UserWorkSpace --> Database +Role --> Database +``` + +**图示来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) + +## 基于注解的访问控制 +DataVines提供了基于注解的访问控制机制,通过自定义注解实现灵活的权限管理。 + +### AuthIgnore注解 +`@AuthIgnore`注解用于标记不需要权限验证的API接口。当方法上标注了该注解时,AuthenticationInterceptor会跳过权限验证流程。 + +```java +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthIgnore { +} +``` + +**代码来源** +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java) + +### CheckTokenExist注解 +`@CheckTokenExist`注解用于标记需要检查Token存在性的API接口。该注解确保请求的Token在系统中存在且有效。 + +```java +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckTokenExist { +} +``` + +**代码来源** +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) + +## API接口权限管理 +DataVines通过拦截器机制对API接口进行统一的权限管理,确保只有经过认证和授权的请求才能访问受保护的资源。 + +### 拦截器配置 +系统在WebMvcConfig中配置了AuthenticationInterceptor,将其应用于所有API路径,但排除了登录接口。 + +```java +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Bean + public AuthenticationInterceptor loginRequiredInterceptor() { + return new AuthenticationInterceptor(); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(loginRequiredInterceptor()) + .addPathPatterns(DataVinesConstants.BASE_API_PATH + "/**") + .excludePathPatterns(DataVinesConstants.BASE_API_PATH + "/login"); + } +} +``` + +**代码来源** +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) + +## 用户角色与工作空间权限模型 +DataVines采用多层级的权限模型,包括用户、工作空间和租户三个核心概念,通过UserWorkSpace实体建立用户与工作空间的关系。 + +### 核心实体关系 +```mermaid +erDiagram +USER { +long id PK +string username +string password +string email +boolean admin +datetime create_time +datetime update_time +} +WORKSPACE { +long id PK +string name +long create_by +datetime create_time +long update_by +datetime update_time +} +TENANT { +long id PK +string tenant +long workspace_id FK +long create_by +datetime create_time +long update_by +datetime update_time +} +USER_WORKSPACE { +long id PK +long user_id FK +long workspace_id FK +long role_id +long create_by +datetime create_time +long update_by +datetime update_time +} +USER ||--o{ USER_WORKSPACE : "拥有" +WORKSPACE ||--o{ USER_WORKSPACE : "包含" +WORKSPACE ||--o{ TENANT : "拥有" +``` + +**图示来源** +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) +- [UserWorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/UserWorkSpace.java) + +## AuthenticationInterceptor实现机制 +AuthenticationInterceptor是DataVines权限控制系统的核心组件,负责处理所有API请求的权限验证。 + +### 核心功能 +- Token提取与验证 +- 用户身份认证 +- 权限检查 +- 上下文设置 + +### 类结构 +```mermaid +classDiagram +class AuthenticationInterceptor { ++TokenManager tokenManager ++UserService userService ++AccessTokenService accessTokenService ++preHandle(HttpServletRequest, HttpServletResponse, Object) boolean ++postHandle(HttpServletRequest, HttpServletResponse, Object, ModelAndView) void ++afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception) void +} +class TokenManager { ++String getUsername(String token) ++String getPassword(String token) ++boolean validateToken(String token, String username, String password) +} +class UserService { ++User getByUsername(String username) +} +class AccessTokenService { ++boolean checkTokenExist(String token) +} +AuthenticationInterceptor --> TokenManager : "使用" +AuthenticationInterceptor --> UserService : "使用" +AuthenticationInterceptor --> AccessTokenService : "使用" +``` + +**图示来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +## 权限验证流程 +DataVines的权限验证流程遵循严格的步骤,确保每个请求都经过完整的认证和授权检查。 + +### 验证流程图 +```mermaid +flowchart TD +Start([请求开始]) --> CheckAnnotation["检查@AuthIgnore注解"] +CheckAnnotation --> IsIgnored{"是否标记@AuthIgnore?"} +IsIgnored --> |是| AllowAccess["允许访问"] +IsIgnored --> |否| ExtractToken["提取Token"] +ExtractToken --> TokenExists{"Token是否存在?"} +TokenExists --> |否| ReturnError["返回TOKEN为空错误"] +TokenExists --> |是| CheckTokenExist["检查@CheckTokenExist注解"] +CheckTokenExist --> NeedCheck{"需要检查Token存在性?"} +NeedCheck --> |是| ValidateTokenExist["验证Token存在性"] +NeedCheck --> |否| GetUsername["获取用户名"] +ValidateTokenExist --> TokenValid{"Token是否存在?"} +TokenValid --> |否| ReturnInvalid["返回无效Token错误"] +TokenValid --> |是| GetUsername +GetUsername --> GetUser["根据用户名获取用户"] +GetUser --> UserExists{"用户是否存在?"} +UserExists --> |否| ReturnInvalid +UserExists --> |是| ValidateToken["验证Token有效性"] +ValidateToken --> TokenValidated{"Token验证通过?"} +TokenValidated --> |否| ReturnInvalid +TokenValidated --> |是| SetContext["设置上下文参数"] +SetContext --> AllowAccess +AllowAccess --> End([请求处理]) +ReturnError --> End +ReturnInvalid --> End +``` + +**图示来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +## 用户租户与工作空间权限关系 +DataVines通过用户、工作空间和租户的层级关系实现复杂的权限管理。 + +### 权限关系说明 +- **用户(User)**:系统的基本身份单元,具有用户名、密码、邮箱等基本信息 +- **工作空间(WorkSpace)**:用户工作的逻辑空间,一个用户可以属于多个工作空间 +- **租户(Tenant)**:工作空间内的资源隔离单元,用于区分不同的执行环境 +- **用户工作空间关系(UserWorkSpace)**:关联用户和工作空间,包含用户在工作空间中的角色信息 + +### 权限继承机制 +权限在层级间具有继承特性: +1. 用户在工作空间中的角色决定了其在该工作空间内的基本权限 +2. 工作空间的租户配置影响用户在该环境下的执行权限 +3. API接口的注解配置可以覆盖默认的权限设置 + +**代码来源** +- [WorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/WorkSpaceServiceImpl.java) +- [UserWorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/UserWorkSpace.java) + +## 配置示例 +以下示例展示了如何配置不同用户角色的访问权限和API端点访问控制。 + +### API接口配置示例 +```java +@RestController +@RequestMapping("/api/users") +public class UserController { + + // 登录接口不需要权限验证 + @PostMapping("/login") + @AuthIgnore + public Result login(@RequestBody UserLogin userLogin) { + // 登录逻辑 + } + + // 获取用户信息需要Token验证 + @GetMapping("/{id}") + public Result getUser(@PathVariable Long id) { + // 获取用户信息逻辑 + } + + // 删除用户需要检查Token存在性 + @DeleteMapping("/{id}") + @CheckTokenExist + public Result deleteUser(@PathVariable Long id) { + // 删除用户逻辑 + } +} +``` + +### 工作空间权限配置 +```java +@Service +public class WorkSpaceService { + + // 邀请用户加入工作空间 + public Long inviteUserIntoWorkspace(InviteUserIntoWorkspace inviteUserIntoWorkspace) { + // 检查用户是否已在工作空间中 + UserWorkSpace userWorkSpace = userWorkSpaceService.getOne( + new QueryWrapper() + .eq(UserWorkSpace::getUserId, user.getId()) + .eq(UserWorkSpace::getWorkspaceId, inviteUserIntoWorkspace.getWorkspaceId())); + + if (userWorkSpace != null) { + throw new DataVinesServerException(Status.USER_IS_IN_WORKSPACE_ERROR); + } + + // 创建用户工作空间关系 + userWorkSpace = new UserWorkSpace(); + userWorkSpace.setUserId(user.getId()); + userWorkSpace.setWorkspaceId(inviteUserIntoWorkspace.getWorkspaceId()); + userWorkSpace.setCreateBy(ContextHolder.getUserId()); + userWorkSpace.setCreateTime(LocalDateTime.now()); + userWorkSpace.setUpdateBy(ContextHolder.getUserId()); + userWorkSpace.setUpdateTime(LocalDateTime.now()); + + userWorkSpaceService.save(userWorkSpace); + + return userWorkSpace.getId(); + } +} +``` + +**代码来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [WorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/WorkSpaceServiceImpl.java) + +## 权限继承与性能优化 +DataVines在权限控制方面实现了有效的继承机制和性能优化策略。 + +### 权限继承规则 +1. **默认继承**:用户在工作空间中的权限默认继承工作空间的配置 +2. **角色覆盖**:特定角色可以拥有超出默认权限的特殊权限 +3. **接口级覆盖**:API接口上的注解可以覆盖用户和角色的默认权限设置 + +### 性能优化措施 +1. **Token缓存**:TokenManager对Token信息进行缓存,减少数据库查询 +2. **批量验证**:对频繁访问的权限检查进行批量处理 +3. **异步检查**:非关键权限检查采用异步方式进行 +4. **连接池**:数据库连接使用连接池管理,提高访问效率 + +## 常见授权问题解决方案 +### Token为空问题 +**问题现象**:客户端请求时未提供Token,导致权限验证失败 +**解决方案**: +1. 确保客户端在请求头中包含Token +2. 或在请求参数中传递Token +3. 检查AuthenticationInterceptor的配置是否正确 + +### 无效Token问题 +**问题现象**:提供的Token无效或已过期 +**解决方案**: +1. 检查Token是否在AccessTokenService中存在 +2. 验证Token的格式和签名 +3. 确认用户账户状态是否正常 + +### 权限不足问题 +**问题现象**:用户有有效Token但无法访问特定资源 +**解决方案**: +1. 检查用户是否属于目标工作空间 +2. 验证用户在工作空间中的角色权限 +3. 确认API接口的权限注解配置 + +### 多工作空间权限问题 +**问题现象**:用户在多个工作空间间切换时权限混乱 +**解决方案**: +1. 确保ContextHolder正确管理用户上下文 +2. 在切换工作空间时清除旧的上下文信息 +3. 验证UserWorkSpace关系的正确性 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256/\346\235\203\351\231\220\346\250\241\345\236\213.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256/\346\235\203\351\231\220\346\250\241\345\236\213.md" new file mode 100644 index 00000000..018b5e04 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256/\346\235\203\351\231\220\346\250\241\345\236\213.md" @@ -0,0 +1,203 @@ +# 权限模型 + + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) +- [UserWorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/UserWorkSpaceService.java) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) +- [WorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/WorkSpaceServiceImpl.java) +- [TenantController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/TenantController.java) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档深入解析DataVines的用户权限体系,详细描述用户、租户和工作空间之间的层级关系和权限继承机制。文档解释了基于角色的访问控制(RBAC)模型的实现方式,包括用户角色定义、权限分配和工作空间隔离策略。同时说明了多租户环境下的数据隔离实现方式,以及用户在不同工作空间间的权限切换机制。通过配置示例展示如何通过application.yaml配置默认权限策略,如何管理用户角色和权限组。最后探讨权限模型的扩展性设计和未来可能的权限精细化控制方向。 + +## 项目结构 +DataVines的权限管理主要集中在`datavines-server`模块中,涉及用户、工作空间和租户三个核心实体。系统采用基于角色的访问控制(RBAC)模型,通过用户-工作空间-租户的层级结构实现权限隔离和继承。权限相关的实体类位于`datavines-server/src/main/java/io/datavines/server/repository/entity/`目录下,服务接口位于`datavines-server/src/main/java/io/datavines/server/repository/service/`目录下。 + +```mermaid +graph TD +A[用户] --> B[工作空间] +B --> C[租户] +D[权限配置] --> B +E[application.yaml] --> D +``` + +**图示来源** +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) + +**章节来源** +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) + +## 核心组件 +DataVines权限模型的核心组件包括用户(User)、工作空间(WorkSpace)和租户(Tenant)三个实体类,以及对应的服务接口和控制器。用户是系统的基本访问主体,工作空间是用户组织和隔离资源的主要单元,租户则是在工作空间内进一步划分执行环境的逻辑单元。这种三层结构实现了灵活的权限管理和资源隔离。 + +**章节来源** +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) + +## 架构概述 +DataVines的权限架构采用典型的RBAC(基于角色的访问控制)模型,通过用户、工作空间和租户的层级关系实现权限继承和隔离。用户首先被分配到一个或多个工作空间,每个工作空间可以包含多个租户。权限控制在工作空间级别进行隔离,确保不同工作空间之间的数据和资源配置相互独立。租户作为工作空间内的执行环境单元,继承工作空间的权限设置。 + +```mermaid +classDiagram +class User { ++Long id ++String username ++String password ++String email ++Long phone ++Boolean admin ++LocalDateTime createTime ++LocalDateTime updateTime +} +class WorkSpace { ++Long id ++String name ++Long createBy ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +class Tenant { ++Long id ++String tenant ++Long workspaceId ++Long createBy ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +class UserWorkSpace { ++Long userId ++Long workspaceId ++Long createBy ++LocalDateTime createTime ++Long updateBy ++LocalDateTime updateTime +} +User "1" --> "0..*" UserWorkSpace : "belongs to" +WorkSpace "1" --> "0..*" UserWorkSpace : "contains" +WorkSpace "1" --> "0..*" Tenant : "contains" +User "1" --> "0..*" WorkSpace : "accesses" +``` + +**图示来源** +- [User.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/User.java) +- [WorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) +- [UserWorkSpace.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/UserWorkSpace.java) + +## 详细组件分析 + +### 用户、工作空间与租户关系分析 +DataVines通过用户、工作空间和租户的层级关系实现复杂的权限管理。用户是系统的基本访问主体,可以加入一个或多个工作空间。工作空间是资源组织和权限隔离的主要单元,每个用户至少需要属于一个工作空间。租户是工作空间内的执行环境,用于隔离不同的运行时配置和资源分配。 + +```mermaid +sequenceDiagram +participant User as 用户 +participant WorkSpace as 工作空间 +participant Tenant as 租户 +participant Service as 服务层 +User->>Service : 请求加入工作空间 +Service->>WorkSpace : 验证工作空间存在性 +WorkSpace-->>Service : 返回验证结果 +Service->>UserWorkSpace : 创建用户-工作空间关联 +UserWorkSpace-->>Service : 返回关联ID +Service->>User : 返回成功结果 +User->>Service : 请求创建工作空间内的租户 +Service->>WorkSpace : 验证用户在工作空间中的权限 +WorkSpace-->>Service : 返回权限验证结果 +Service->>Tenant : 创建租户实例 +Tenant-->>Service : 返回租户信息 +Service->>User : 返回租户创建结果 +``` + +**图示来源** +- [WorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/WorkSpaceServiceImpl.java) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) +- [TenantController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/TenantController.java) + +**章节来源** +- [WorkSpaceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/WorkSpaceServiceImpl.java) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) +- [TenantController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/TenantController.java) + +### 权限继承与隔离机制 +DataVines的权限继承机制基于工作空间和租户的层级结构。当用户被添加到工作空间时,自动继承该工作空间的基本访问权限。租户作为工作空间的子单元,继承工作空间的权限设置,同时可以进行更细粒度的权限配置。这种设计实现了权限的层级继承和有效隔离。 + +```mermaid +flowchart TD +A[用户登录] --> B{用户是否属于工作空间?} +B --> |否| C[提示用户需要加入工作空间] +B --> |是| D[加载用户在工作空间的权限] +D --> E{工作空间是否有租户?} +E --> |否| F[使用工作空间默认配置] +E --> |是| G[列出可用租户] +G --> H[用户选择租户] +H --> I[加载租户特定配置] +I --> J[进入系统] +``` + +**图示来源** +- [UserWorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/UserWorkSpaceService.java) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) + +**章节来源** +- [UserWorkSpaceService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/UserWorkSpaceService.java) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) + +## 依赖分析 +DataVines权限模型的实现依赖于多个核心组件和服务。用户管理依赖于Spring Security框架进行身份验证,工作空间和租户管理依赖于MyBatis-Plus进行数据持久化操作。权限配置的加载和刷新依赖于Spring的配置管理机制。各组件之间的依赖关系清晰,通过服务接口进行解耦。 + +```mermaid +graph TD +A[用户界面] --> B[API控制器] +B --> C[服务层] +C --> D[数据访问层] +D --> E[数据库] +F[配置文件] --> C +G[Spring Security] --> B +H[MyBatis-Plus] --> D +``` + +**图示来源** +- [TenantController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/TenantController.java) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) +- [Tenant.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/Tenant.java) + +**章节来源** +- [TenantController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/TenantController.java) +- [TenantService.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/TenantService.java) + +## 性能考虑 +在权限模型设计中,DataVines考虑了性能优化的多个方面。通过缓存用户-工作空间关联关系,减少数据库查询次数。采用分页查询机制获取工作空间用户列表,避免一次性加载大量数据。权限验证过程尽量在内存中完成,减少对数据库的频繁访问。这些优化措施确保了系统在用户规模扩大时仍能保持良好的响应性能。 + +## 故障排除指南 +当遇到权限相关问题时,可以按照以下步骤进行排查:首先检查用户是否已正确加入目标工作空间;其次验证工作空间是否存在且状态正常;然后确认租户配置是否正确;最后检查application.yaml中的权限相关配置是否符合预期。通过查看系统日志可以获取更详细的错误信息,帮助定位具体问题。 + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [TenantController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/TenantController.java) + +## 结论 +DataVines的权限模型通过用户、工作空间和租户的三层架构,实现了灵活而安全的访问控制。基于RBAC的权限管理机制,结合工作空间级别的数据隔离,满足了多租户环境下的复杂权限需求。系统的扩展性设计允许未来引入更细粒度的权限控制,如基于属性的访问控制(ABAC)或动态权限策略。通过合理的配置和管理,可以有效保障系统的安全性和可用性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256/\350\256\277\351\227\256\346\216\247\345\210\266.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256/\350\256\277\351\227\256\346\216\247\345\210\266.md" new file mode 100644 index 00000000..9f0125d6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\216\210\346\235\203\351\205\215\347\275\256/\350\256\277\351\227\256\346\216\247\345\210\266.md" @@ -0,0 +1,300 @@ +# 访问控制 + + +**本文档引用的文件** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) + + +## 目录 +1. [引言](#引言) +2. [基于注解的访问控制机制](#基于注解的访问控制机制) +3. [认证拦截器实现原理](#认证拦截器实现原理) +4. [API请求权限验证流程](#api请求权限验证流程) +5. [代码示例与使用方法](#代码示例与使用方法) +6. [性能优化建议](#性能优化建议) +7. [安全漏洞防范措施](#安全漏洞防范措施) +8. [结论](#结论) + +## 引言 +DataVines平台采用基于注解的访问控制机制来保护其API接口的安全性。该机制通过JWT令牌验证和权限检查确保只有经过身份验证的用户才能访问受保护的资源。本文档详细介绍了@AuthIgnore注解的使用场景和实现原理,解释了AuthenticationInterceptor拦截器如何实现JWT令牌验证和权限检查,并描述了API请求的完整权限验证流程。 + +## 基于注解的访问控制机制 + +DataVines的访问控制机制主要依赖于自定义注解来实现灵活的权限管理。核心注解包括@AuthIgnore和@CheckTokenExist,它们被应用于控制器方法上以控制访问权限。 + +### @AuthIgnore注解 + +@AuthIgnore注解用于标记不需要进行身份验证的方法。当一个方法被@AuthIgnore注解修饰时,AuthenticationInterceptor会跳过对该方法的权限检查,允许匿名访问。 + +```java +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthIgnore { +} +``` + +**使用场景**: +- 登录接口:允许用户在未登录状态下进行身份验证 +- 注册接口:新用户注册时无需提供有效令牌 +- 公共API:提供给外部系统调用的开放接口 + +**实现原理**: +在AuthenticationInterceptor的preHandle方法中,首先检查目标方法是否包含@AuthIgnore注解。如果存在该注解,则直接返回true,跳过后续的权限验证流程。 + +**节来源** +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java#L24-L27) + +### @CheckTokenExist注解 + +@CheckTokenExist注解用于强制检查令牌在数据库中的存在性。与基本的JWT验证不同,此注解确保令牌不仅有效,而且在系统的访问令牌表中存在。 + +```java +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckTokenExist { +} +``` + +**使用场景**: +- 敏感操作:如用户信息修改、密码重置等高风险操作 +- 管理员功能:后台管理相关的所有接口 +- 数据删除:涉及数据删除或修改的重要操作 + +**实现原理**: +当方法被@CheckTokenExist注解修饰时,拦截器会调用AccessTokenService的checkTokenExist方法,验证令牌是否存在于数据库中。如果不存在,则抛出INVALID_TOKEN异常。 + +**节来源** +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java#L24-L27) + +## 认证拦截器实现原理 + +AuthenticationInterceptor是DataVines访问控制的核心组件,它实现了Spring MVC的HandlerInterceptor接口,在请求处理前进行权限验证。 + +### 拦截器注册与配置 + +在WebMvcConfig配置类中,AuthenticationInterceptor被注册为全局拦截器,并设置了拦截路径模式。 + +```mermaid +flowchart TD +A[请求进入] --> B{是否为API请求?} +B --> |是| C{是否为登录接口?} +C --> |是| D[跳过拦截] +C --> |否| E[执行AuthenticationInterceptor] +B --> |否| F[正常处理] +``` + +**图来源** +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java#L43-L48) + +**节来源** +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java#L38-L48) + +### 权限验证流程 + +AuthenticationInterceptor的preHandle方法实现了完整的权限验证流程: + +1. **方法注解检查**:首先检查是否存在@AuthIgnore注解,如果有则直接放行 +2. **令牌获取**:从请求头或参数中获取Authorization令牌 +3. **令牌存在性检查**:根据@CheckTokenExist注解决定是否检查令牌在数据库中的存在性 +4. **用户身份验证**:通过TokenManager解析令牌中的用户名,并从数据库中获取用户信息 +5. **令牌有效性验证**:验证令牌的签名、过期时间以及用户名和密码的匹配性 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Interceptor as AuthenticationInterceptor +participant TokenManager as TokenManager +participant UserService as UserService +Client->>Interceptor : 发送API请求 +Interceptor->>Interceptor : 检查@AuthIgnore注解 +alt 存在@AuthIgnore +Interceptor-->>Client : 直接放行 +else +Interceptor->>Interceptor : 获取Authorization令牌 +Interceptor->>Interceptor : 检查令牌是否存在 +Interceptor->>TokenManager : 解析令牌获取用户名 +TokenManager-->>Interceptor : 返回用户名 +Interceptor->>UserService : 根据用户名查询用户 +UserService-->>Interceptor : 返回用户信息 +Interceptor->>TokenManager : 验证令牌有效性 +TokenManager-->>Interceptor : 返回验证结果 +alt 验证成功 +Interceptor-->>Client : 允许请求继续 +else +Interceptor-->>Client : 返回401错误 +end +end +``` + +**图来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L54-L104) + +**节来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L42-L115) + +## API请求权限验证流程 + +### 令牌解析与验证 + +DataVines使用JWT(JSON Web Token)作为身份验证机制。TokenManager类负责令牌的生成、解析和验证。 + +#### 令牌结构 +DataVines的JWT令牌包含以下声明(claims): +- `un` (TOKEN_USER_NAME): 用户名 +- `up` (TOKEN_USER_PASSWORD): 用户密码 +- `ct` (TOKEN_CREATE_TIME): 令牌创建时间 + +#### 令牌验证步骤 +1. **提取令牌**:从Authorization请求头中提取Bearer令牌 +2. **解析声明**:使用预共享密钥解码JWT令牌,获取其中的声明信息 +3. **验证签名**:确保令牌未被篡改 +4. **检查过期时间**:验证令牌是否在有效期内 +5. **用户信息匹配**:确认令牌中的用户名和密码与数据库中的记录匹配 + +```mermaid +flowchart TD +A[开始] --> B[从请求头获取令牌] +B --> C{令牌是否存在?} +C --> |否| D[尝试从参数获取] +D --> E{参数中是否存在?} +E --> |否| F[返回TOKEN_IS_NULL_ERROR] +E --> |是| G[使用参数中的令牌] +C --> |是| G +G --> H[解析JWT令牌] +H --> I{解析成功?} +I --> |否| J[返回INVALID_TOKEN] +I --> |是| K[获取用户名] +K --> L[查询用户信息] +L --> M{用户是否存在?} +M --> |否| J +M --> |是| N[验证令牌有效性] +N --> O{验证通过?} +O --> |否| J +O --> |是| P[设置用户上下文] +P --> Q[允许请求继续] +``` + +**图来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L163-L167) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L89-L98) + +**节来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L132-L196) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L74-L98) + +### 上下文管理 + +在权限验证成功后,系统会将用户信息存储在请求上下文中,以便后续的业务逻辑使用。 + +```java +request.setAttribute(DataVinesConstants.LOGIN_USER, user); +ContextHolder.setParam(DataVinesConstants.LOGIN_USER, user); +ContextHolder.setParam(DataVinesConstants.TOKEN, token); +``` + +ContextHolder使用ThreadLocal来存储当前线程的上下文信息,确保线程安全。在请求结束后,afterCompletion方法会清理这些上下文信息,防止内存泄漏。 + +**节来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L94-L102) + +## 代码示例与使用方法 + +### 控制器方法示例 + +以下是一些典型的控制器方法使用示例: + +```java +@RestController +@RequestMapping("/api/v1/user") +public class UserController { + + @PostMapping("/login") + @AuthIgnore + public Result login(@RequestBody LoginRequest loginRequest) { + // 登录逻辑,无需身份验证 + } + + @GetMapping("/profile") + public Result getProfile() { + // 需要身份验证,但不检查令牌存在性 + } + + @PutMapping("/update") + @CheckTokenExist + public Result update(@RequestBody UserUpdateRequest request) { + // 需要身份验证,并检查令牌在数据库中的存在性 + } +} +``` + +**节来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +### 未授权访问处理 + +当权限验证失败时,系统会抛出DataVinesServerException异常,该异常会被全局异常处理器捕获并转换为适当的HTTP响应。 + +```java +throw new DataVinesServerException(Status.TOKEN_IS_NULL_ERROR); +throw new DataVinesServerException(Status.INVALID_TOKEN, token); +``` + +这些异常会返回相应的错误码和消息,客户端可以根据这些信息进行适当的错误处理。 + +**节来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L79-L86) + +## 性能优化建议 + +### 权限缓存策略 + +为了提高权限验证的性能,可以实施以下缓存策略: + +1. **用户信息缓存**:将频繁访问的用户信息缓存在Redis中,减少数据库查询次数 +2. **令牌状态缓存**:对于@CheckTokenExist检查,可以缓存令牌的有效状态,避免重复的数据库查询 +3. **JWT解析结果缓存**:在单个请求处理过程中,缓存JWT的解析结果,避免多次解析同一个令牌 + +```mermaid +graph TD +A[请求到达] --> B{令牌已解析?} +B --> |是| C[使用缓存的解析结果] +B --> |否| D[解析JWT令牌] +D --> E[缓存解析结果] +E --> C +C --> F[继续权限验证] +``` + +**图来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +### 减少数据库查询 + +通过以下方式减少数据库查询次数: +- 在TokenManager中缓存用户的密码信息 +- 使用批量查询替代多次单个查询 +- 实现连接池以提高数据库连接效率 + +## 安全漏洞防范措施 + +### JWT安全最佳实践 + +1. **使用强密钥**:确保jwt.token.secret配置项使用足够长且随机的密钥 +2. **合理设置过期时间**:通过jwt.token.timeout配置合理的令牌过期时间 +3. **HTTPS传输**:始终通过HTTPS传输JWT令牌,防止中间人攻击 +4. **令牌刷新机制**:实现令牌刷新功能,定期更新令牌以降低泄露风险 + +### 防止常见攻击 + +1. **重放攻击防护**:通过检查令牌的创建时间,拒绝过期的请求 +2. **暴力破解防护**:对登录接口实施失败次数限制 +3. **令牌泄露防护**:提供令牌撤销功能,允许用户主动注销令牌 +4. **输入验证**:对所有输入参数进行严格的验证和清理 + +## 结论 + +DataVines的基于注解的访问控制机制提供了一种灵活而强大的权限管理方案。通过@AuthIgnore和@CheckTokenExist注解,开发者可以精确控制每个API接口的访问权限。AuthenticationInterceptor拦截器实现了完整的JWT令牌验证流程,确保了系统的安全性。建议在实际使用中结合性能优化策略和安全防护措施,以构建既安全又高效的API服务。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256/\345\212\240\345\257\206\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256/\345\212\240\345\257\206\347\256\241\347\220\206.md" new file mode 100644 index 00000000..e4c61802 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256/\345\212\240\345\257\206\347\256\241\347\220\206.md" @@ -0,0 +1,321 @@ +# 加密管理 + + +**本文档中引用的文件** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + + +## 目录 +1. [引言](#引言) +2. [加密机制概述](#加密机制概述) +3. [CryptionUtils类实现原理](#cryptionutils类实现原理) +4. [密钥管理与配置](#密钥管理与配置) +5. [加密算法与参数配置](#加密算法与参数配置) +6. [敏感数据加密解密流程](#敏感数据加密解密流程) +7. [密钥轮换最佳实践](#密钥轮换最佳实践) +8. [性能影响与安全考量](#性能影响与安全考量) +9. [总结](#总结) + +## 引言 + +DataVines平台为保护敏感数据安全,实现了一套完整的加密管理机制。本文档详细说明DataVines的加密机制,重点介绍CryptionUtils类的实现原理、加密算法配置、密钥管理策略以及安全最佳实践。系统主要针对数据源连接参数等敏感信息进行加密存储,确保数据在传输和存储过程中的安全性。 + +## 加密机制概述 + +DataVines采用AES对称加密算法保护敏感数据,主要应用于数据源配置信息的加密存储。系统通过CryptionUtils工具类提供加密和解密功能,结合配置文件中的密钥管理策略,实现了敏感数据的安全保护。加密机制的核心组件包括: + +- **CryptionUtils类**:提供AES加密和解密的静态方法 +- **密钥管理**:通过配置文件定义加密密钥 +- **加密流程**:在数据存储前加密,在数据读取后解密 +- **安全防护**:防止敏感信息在日志中明文显示 + +该机制确保了数据源连接信息(如密码)在数据库中的加密存储,同时在应用程序需要使用时能够安全地解密。 + +**Section sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L25-L85) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L112-L255) + +## CryptionUtils类实现原理 + +CryptionUtils类是DataVines加密功能的核心实现,提供了基于AES算法的加密和解密方法。该类的实现原理如下: + +```mermaid +classDiagram +class CryptionUtils { ++static String ALGORITHM ++static String TRANSFORMATION ++static String IV_PARAMETER_SPE ++static String encryptByAES(String input, String key) ++static String decryptByAES(String input, String key) +-static byte[] hexStringToBytes(String hexString) +-static String bytesToHexString(byte[] sources) +} +``` + +**Diagram sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L25-L85) + +### 加密算法配置 + +CryptionUtils类定义了以下静态字段来配置加密参数: + +- **ALGORITHM**: 加密算法,固定为"AES" +- **TRANSFORMATION**: 转换模式,设置为"AES/CBC/PKCS5Padding" +- **IV_PARAMETER_SPE**: 初始化向量(IV),值为"0123456789ABCEDF" + +### 加密流程 + +`encryptByAES`方法的执行流程如下: +1. 通过`Cipher.getInstance(TRANSFORMATION)`获取加密实例 +2. 使用密钥字符串创建`SecretKeySpec`对象 +3. 使用固定的IV创建`IvParameterSpec`对象 +4. 初始化加密模式 +5. 执行加密操作 +6. 将加密后的字节数组转换为十六进制字符串 + +### 解密流程 + +`decryptByAES`方法的执行流程与加密类似,但初始化为解密模式,并将十六进制字符串转换回字节数组进行解密。 + +### 辅助方法 + +类中还包含两个辅助方法: +- `hexStringToBytes`: 将十六进制字符串转换为字节数组 +- `bytesToHexString`: 将字节数组转换为十六进制字符串 + +这些方法确保了加密结果可以安全地作为字符串存储和传输。 + +**Section sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L32-L85) + +## 密钥管理与配置 + +DataVines的密钥管理采用配置驱动的方式,通过层级化的配置系统实现密钥的灵活管理。 + +### 配置优先级 + +系统遵循以下配置优先级顺序: +1. 系统属性(最高优先级) +2. common.properties文件 +3. 默认值(最低优先级) + +```mermaid +flowchart TD +A[系统属性] --> B{是否存在aes.key?} +C[common.properties] --> B +D[默认值] --> B +B --> |是| E[使用指定密钥] +B --> |否| F[使用默认密钥] +``` + +**Diagram sources** +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java#L124-L129) + +### 配置实现 + +密钥配置通过`CommonPropertyUtils`类管理,相关常量定义如下: + +```java +public static final String AES_KEY = "aes.key"; +public static final String AES_KEY_DEFAULT = "1234567890123456"; +``` + +系统在启动时加载`common.properties`文件,并允许通过JVM系统属性覆盖配置值,提供了灵活的密钥管理方式。 + +**Section sources** +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java#L82-L84) +- [common.properties](file://datavines-common/src/main/resources/common.properties) + +## 加密算法与参数配置 + +DataVines采用标准的AES加密算法配置,确保了加密的安全性和兼容性。 + +### 算法参数 + +| 参数 | 值 | 说明 | +|------|-----|------| +| 算法 | AES | 高级加密标准 | +| 模式 | CBC | 密码块链接模式 | +| 填充 | PKCS5Padding | PKCS#5填充方案 | +| 密钥长度 | 128位 | 默认密钥长度 | +| IV长度 | 16字节 | 初始化向量 | + +### 配置文件设置 + +虽然主要加密参数在代码中硬编码,但可以通过以下方式自定义: + +1. **密钥自定义**:通过系统属性或配置文件修改`aes.key` +2. **环境变量**:在部署时通过环境变量设置密钥 + +```yaml +# application.yaml中不直接配置加密参数 +# 但可以通过系统属性设置 +-Daes.key=your_custom_key +``` + +### 安全建议 + +- 密钥长度:建议使用128位或256位密钥 +- IV管理:当前使用固定IV,建议在生产环境中使用随机IV +- 密钥存储:避免在代码中硬编码密钥,应使用密钥管理系统 + +**Section sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L26-L31) + +## 敏感数据加密解密流程 + +DataVines在数据源管理场景中实现了完整的加密解密流程,确保敏感信息的安全。 + +### 数据源加密流程 + +```mermaid +sequenceDiagram +participant UI as 用户界面 +participant Service as DataSourceService +participant Crypto as CryptionUtils +participant DB as 数据库 +UI->>Service : 创建/更新数据源 +Service->>Crypto : encryptByAES(param, key) +Crypto-->>Service : 返回加密字符串 +Service->>DB : 存储加密后的参数 +DB-->>Service : 存储确认 +Service-->>UI : 操作成功 +``` + +**Diagram sources** +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L112-L115) + +### 数据源解密流程 + +```mermaid +sequenceDiagram +participant UI as 用户界面 +participant Service as DataSourceService +participant Crypto as CryptionUtils +participant DB as 数据库 +UI->>Service : 查询数据源 +Service->>DB : 获取加密参数 +DB-->>Service : 返回加密字符串 +Service->>Crypto : decryptByAES(encrypted, key) +Crypto-->>Service : 返回明文参数 +Service->>UI : 显示数据源信息 +Note over Service,UI : 敏感字段在显示前会被掩码处理 +``` + +**Diagram sources** +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L212-L215) + +### 代码示例 + +以下是敏感数据加密和解密的使用示例: + +```java +// 加密示例 +String plaintext = "{\"username\":\"admin\",\"password\":\"secret\"}"; +String key = CommonPropertyUtils.getString( + CommonPropertyUtils.AES_KEY, + CommonPropertyUtils.AES_KEY_DEFAULT +); +String encrypted = CryptionUtils.encryptByAES(plaintext, key); + +// 解密示例 +String decrypted = CryptionUtils.decryptByAES(encrypted, key); +``` + +**Section sources** +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L112-L255) + +## 密钥轮换最佳实践 + +尽管当前实现中密钥轮换机制较为基础,但可以遵循以下最佳实践来增强安全性。 + +### 密钥轮换策略 + +1. **定期轮换**:建议每90天更换一次加密密钥 +2. **多版本支持**:系统应支持多个密钥版本,以便平滑过渡 +3. **自动化流程**:建立自动化的密钥轮换流程 + +### 实施建议 + +```mermaid +flowchart TD +A[生成新密钥] --> B[更新配置] +B --> C[重新加密数据] +C --> D[验证解密] +D --> E[删除旧密钥] +E --> F[完成轮换] +``` + +### 安全注意事项 + +- **备份**:在轮换前备份所有加密数据 +- **测试**:在生产环境应用前进行充分测试 +- **监控**:监控密钥轮换过程中的异常情况 +- **审计**:记录密钥轮换操作日志 + +当前系统实现中,密钥轮换需要手动修改配置并重新加密所有数据,建议未来版本中实现更完善的密钥管理功能。 + +**Section sources** +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java#L82-L84) + +## 性能影响与安全考量 + +### 性能影响 + +AES加密对系统性能的影响主要体现在: + +- **CPU开销**:加密解密操作消耗CPU资源 +- **内存使用**:临时字节数组的创建和销毁 +- **延迟增加**:每个数据源操作增加毫秒级延迟 + +在实际测试中,单次加密操作的平均耗时在1-5毫秒之间,对整体系统性能影响较小。 + +### 安全考量 + +#### 已实现的安全措施 + +- **CBC模式**:使用密码块链接模式,增加加密安全性 +- **PKCS5填充**:标准填充方案,防止某些类型的攻击 +- **密钥管理**:通过配置文件和系统属性管理密钥 +- **日志防护**:敏感信息在日志中被掩码处理 + +#### 改进建议 + +1. **IV随机化**:当前使用固定IV,建议改为随机IV以增强安全性 +2. **密钥派生**:使用PBKDF2等算法从密码派生密钥 +3. **完整性验证**:添加HMAC验证加密数据的完整性 +4. **侧信道防护**:实现恒定时间比较等防护措施 + +#### 侧信道攻击防护 + +虽然当前实现未专门针对侧信道攻击进行优化,但可以采取以下措施: + +- **恒定时间比较**:确保字符串比较操作的时间与内容无关 +- **内存清理**:及时清理包含敏感信息的内存 +- **错误信息模糊化**:避免通过错误信息泄露加密细节 + +**Section sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) + +## 总结 + +DataVines的加密管理机制基于AES算法实现了敏感数据的安全保护,通过CryptionUtils工具类提供了可靠的加密解密功能。系统采用配置驱动的密钥管理策略,结合默认值和可覆盖的配置机制,实现了灵活性和安全性的平衡。 + +核心优势包括: +- 使用行业标准的AES加密算法 +- 清晰的加密解密流程 +- 配置化的密钥管理 +- 与业务逻辑的良好集成 + +改进建议: +- 实现更安全的IV管理机制 +- 增强密钥轮换支持 +- 添加加密数据完整性验证 +- 优化侧信道攻击防护 + +总体而言,DataVines的加密机制为敏感数据保护提供了坚实的基础,通过持续优化可以进一步提升系统的安全性和可靠性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256.md" new file mode 100644 index 00000000..7e231e1d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256.md" @@ -0,0 +1,321 @@ +# 数据安全配置 + + +**本文档引用的文件** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [constants.ts](file://datavines-ui/src/utils/constants.ts) + + +## 目录 +1. [引言](#引言) +2. [敏感数据加密机制](#敏感数据加密机制) +3. [密码存储与验证策略](#密码存储与验证策略) +4. [日志敏感信息过滤](#日志敏感信息过滤) +5. [配置示例](#配置示例) +6. [数据泄露防护建议](#数据泄露防护建议) +7. [加密性能考量](#加密性能考量) +8. [密钥轮换策略](#密钥轮换策略) + +## 引言 +DataVines提供了一套完整的数据安全保护机制,确保敏感数据在存储、传输和日志记录过程中的安全性。本文档详细说明了DataVines的数据保护机制,包括敏感数据加密(CryptionUtils)、密码存储策略、日志中的敏感信息过滤等核心安全功能。通过分析CryptionUtils的加密算法和密钥管理、PasswordFilterUtils的密码验证规则,以及SensitiveDataConverter的日志脱敏机制,为系统管理员和开发人员提供全面的安全配置指导。 + +**本文档引用的文件** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) + +## 敏感数据加密机制 + +DataVines使用CryptionUtils类实现敏感数据的加密和解密功能,采用行业标准的AES加密算法保护数据安全。 + +### 加密算法与实现 +CryptionUtils实现了基于AES(Advanced Encryption Standard)的加密机制,具体配置如下: +- **加密算法**: AES +- **转换模式**: AES/CBC/PKCS5Padding +- **初始化向量(IV)**: "0123456789ABCEDF" +- **填充模式**: PKCS5Padding + +该加密方案采用CBC(Cipher Block Chaining)模式,通过将前一个密文块与当前明文块进行异或操作,增强了加密的安全性,防止相同明文产生相同密文。 + +### 加密流程 +```mermaid +flowchart TD +Start([开始加密]) --> ValidateInput["验证输入参数"] +ValidateInput --> InputValid{"输入有效?"} +InputValid --> |否| ReturnError["返回错误"] +InputValid --> |是| CreateCipher["创建Cipher实例"] +CreateCipher --> CreateKeySpec["创建SecretKeySpec"] +CreateKeySpec --> CreateIvSpec["创建IvParameterSpec"] +CreateIvSpec --> InitCipher["初始化Cipher为加密模式"] +InitCipher --> EncryptData["执行加密操作"] +EncryptData --> ConvertToHex["转换为十六进制字符串"] +ConvertToHex --> ReturnResult["返回加密结果"] +``` + +**Diagram sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L33-L41) + +### 解密流程 +```mermaid +flowchart TD +Start([开始解密]) --> ValidateInput["验证输入参数"] +ValidateInput --> InputValid{"输入有效?"} +InputValid --> |否| ReturnError["返回错误"] +InputValid --> |是| ConvertFromHex["从十六进制转换为字节数组"] +ConvertFromHex --> CreateCipher["创建Cipher实例"] +CreateCipher --> CreateKeySpec["创建SecretKeySpec"] +CreateKeySpec --> CreateIvSpec["创建IvParameterSpec"] +CreateIvSpec --> InitCipher["初始化Cipher为解密模式"] +InitCipher --> DecryptData["执行解密操作"] +DecryptData --> ConvertToString["转换为字符串"] +ConvertToString --> ReturnResult["返回解密结果"] +``` + +**Diagram sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L43-L52) + +**Section sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L25-L85) + +## 密码存储与验证策略 + +DataVines实施了多层次的密码安全策略,包括密码复杂度验证和安全存储机制。 + +### 密码复杂度要求 +系统对用户密码实施严格的复杂度要求,确保密码安全性: + +| 验证规则 | 描述 | 实现位置 | +|---------|------|---------| +| 长度要求 | 密码长度必须在6-20个字符之间 | CommonConstants.java | +| 复杂度要求 | 必须包含数字、大写字母、小写字母和特殊字符 | constants.ts | +| 正则表达式 | `^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$` | constants.ts | + +```mermaid +flowchart TD +Start([密码验证开始]) --> CheckLength["检查密码长度"] +CheckLength --> LengthValid{"长度6-20?"} +LengthValid --> |否| ReturnInvalid["密码无效"] +LengthValid --> |是| CheckDigit["检查是否包含数字"] +CheckDigit --> HasDigit{"包含数字?"} +HasDigit --> |否| ReturnInvalid +HasDigit --> |是| CheckUpperCase["检查是否包含大写字母"] +CheckUpperCase --> HasUpperCase{"包含大写字母?"} +HasUpperCase --> |否| ReturnInvalid +HasUpperCase --> |是| CheckLowerCase["检查是否包含小写字母"] +CheckLowerCase --> HasLowerCase{"包含小写字母?"} +HasLowerCase --> |否| ReturnInvalid +HasLowerCase --> |是| CheckSpecialChar["检查是否包含特殊字符"] +CheckSpecialChar --> HasSpecialChar{"包含特殊字符?"} +HasSpecialChar --> |否| ReturnInvalid +HasSpecialChar --> |是| ReturnValid["密码有效"] +``` + +**Diagram sources** +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java#L171) +- [constants.ts](file://datavines-ui/src/utils/constants.ts#L2) + +### 密码验证实现 +PasswordFilterUtils类负责处理密码相关的安全操作,主要功能包括: + +1. **密码模式匹配**: 使用正则表达式识别日志中的密码字段 +2. **密码脱敏处理**: 将识别到的密码替换为掩码 +3. **灵活的脱敏策略**: 支持替换为固定掩码或完全移除 + +```mermaid +classDiagram +class PasswordFilterUtils { ++convertPassword(Pattern, String) String ++convertPasswordToNULL(Pattern, String) String +-passwordHandler(Pattern, String, boolean) String +} +class SensitiveLogUtils { ++maskDataSourcePwd(String) String +} +class StringUtils { ++isNotEmpty(CharSequence) boolean +} +PasswordFilterUtils --> SensitiveLogUtils : "使用" +PasswordFilterUtils --> StringUtils : "使用" +PasswordFilterUtils --> Pattern : "依赖" +``` + +**Diagram sources** +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L25-L77) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java#L24-L39) + +**Section sources** +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L25-L77) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java#L171) +- [constants.ts](file://datavines-ui/src/utils/constants.ts#L2) + +## 日志敏感信息过滤 + +DataVines通过日志过滤机制防止敏感信息(如密码)被记录到日志文件中,确保日志的安全性。 + +### 日志脱敏架构 +系统采用Logback框架的转换规则(conversionRule)机制,在日志输出前对敏感信息进行脱敏处理。 + +```mermaid +sequenceDiagram +participant Application as "应用程序" +participant Logger as "Logger" +participant Converter as "SensitiveDataConverter" +participant Filter as "PasswordFilterUtils" +participant Output as "日志输出" +Application->>Logger : 记录日志消息 +Logger->>Converter : 调用转换器 +Converter->>Converter : 获取格式化消息 +Converter->>Filter : convertPassword(PWD_PATTERN, msg) +Filter->>Filter : passwordHandler(pwdPattern, logMsg, false) +Filter->>Filter : 使用正则表达式匹配密码 +Filter->>Filter : 调用maskDataSourcePwd进行掩码 +Filter-->>Converter : 返回脱敏后的消息 +Converter-->>Logger : 返回处理后的消息 +Logger->>Output : 输出脱敏日志 +``` + +**Diagram sources** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L29-L60) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L25-L77) + +### 敏感数据转换器 +SensitiveDataConverter继承自Logback的MessageConverter,实现了日志消息的转换功能: + +- **正则表达式匹配**: 识别JSON格式中的密码字段 +- **双模式匹配**: 支持转义和非转义的JSON字符串 +- **实时脱敏**: 在日志输出前即时处理敏感信息 + +```java +// 正则表达式定义 +public static final String DATASOURCE_PASSWORD_REGEX = "(?<=(\\\\\"password\\\\\":\\\\\")).*?(?=(\\\\\"))"; +public static final String DATASOURCE_PASSWORD_REGEX_1 = "(?<=(\"password\":\")).*?(?=(\"))"; +``` + +### 日志过滤配置 +在server-logback.xml中配置了敏感数据转换器: + +```xml + +``` + +此配置将"message"关键字映射到自定义的SensitiveDataConverter类,确保所有日志消息都经过脱敏处理。 + +**Section sources** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L29-L60) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L33-L34) + +## 配置示例 + +### 加密强度配置 +虽然加密算法和模式在代码中硬编码,但可以通过外部配置管理加密密钥: + +```yaml +# application.yaml - 数据源配置示例 +spring: + datasource: + url: jdbc:postgresql://127.0.0.1:5432/datavines + username: postgres + password: ${ENCRYPTED_PASSWORD_KEY} # 使用加密的密码 +``` + +### 密码复杂度配置 +密码复杂度规则在多个位置定义,确保前后端一致性: + +```properties +# common.properties - 后端密码规则 +REG_USER_PASSWORD=. {6,20} +``` + +```typescript +// constants.ts - 前端密码规则 +export const PWD_REG = /^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]). *$/; +``` + +### 敏感字段过滤规则 +日志脱敏规则通过正则表达式定义,可扩展以支持更多敏感字段: + +```java +// SensitiveDataConverter.java - 敏感字段正则表达式 +public static final String DATASOURCE_PASSWORD_REGEX = "(?<=(\\\\\"password\\\\\":\\\\\")).*?(?=(\\\\\"))"; +public static final String DATASOURCE_PASSWORD_REGEX_1 = "(?<=(\"password\":\")).*?(?=(\"))"; +``` + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L23-L27) +- [common.properties](file://datavines-common/src/main/resources/common.properties#L18-L25) +- [constants.ts](file://datavines-ui/src/utils/constants.ts#L2) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L34-L39) + +## 数据泄露防护建议 + +### 最佳实践 +1. **密钥管理**: 将加密密钥存储在安全的密钥管理系统中,避免硬编码 +2. **最小权限原则**: 为数据库用户分配最小必要权限 +3. **定期审计**: 定期审查日志文件,确保没有敏感信息泄露 +4. **网络加密**: 在传输敏感数据时使用SSL/TLS加密 + +### 安全配置检查清单 +- [ ] 确保所有密码字段都经过加密存储 +- [ ] 验证日志脱敏机制正常工作 +- [ ] 检查密码复杂度策略是否强制执行 +- [ ] 确认加密密钥的安全存储 +- [ ] 定期轮换加密密钥 + +**Section sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) + +## 加密性能考量 + +### 性能影响分析 +AES加密对系统性能的影响相对较小,但大规模数据加密仍需考虑: + +| 操作 | 时间复杂度 | 空间复杂度 | 性能建议 | +|------|-----------|-----------|---------| +| 单次加密 | O(n) | O(n) | 适用于小数据量 | +| 批量加密 | O(n) | O(n) | 建议分批处理 | +| 密钥生成 | O(1) | O(1) | 可缓存重复使用 | + +### 优化策略 +1. **缓存加密结果**: 对于频繁访问的静态数据,可缓存加密结果 +2. **异步加密**: 对于大数据量的加密操作,考虑使用异步处理 +3. **批量处理**: 将多个小数据块合并为大数据块进行加密,减少加密开销 +4. **硬件加速**: 在支持的环境中使用硬件加密加速 + +**Section sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) + +## 密钥轮换策略 + +### 密钥管理建议 +虽然当前实现中密钥作为参数传入,但建议采用以下密钥管理策略: + +1. **定期轮换**: 每90天轮换一次加密密钥 +2. **多版本支持**: 支持新旧密钥并存,确保平滑过渡 +3. **安全存储**: 使用专门的密钥管理系统(如Hashicorp Vault)存储密钥 +4. **访问控制**: 严格控制密钥的访问权限 + +### 密钥轮换流程 +```mermaid +flowchart TD +Start([开始密钥轮换]) --> GenerateNewKey["生成新密钥"] +GenerateNewKey --> StoreNewKey["安全存储新密钥"] +StoreNewKey --> UpdateConfig["更新系统配置"] +UpdateConfig --> TestEncryption["测试加密功能"] +TestEncryption --> TestDecryption["测试解密功能"] +TestDecryption --> ValidateData["验证数据完整性"] +ValidateData --> ScheduleOldKeyRetirement["计划旧密钥退役"] +ScheduleOldKeyRetirement --> Monitor["监控系统运行"] +Monitor --> RetireOldKey["退役旧密钥"] +RetireOldKey --> Complete["密钥轮换完成"] +``` + +**Section sources** +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256/\346\227\245\345\277\227\345\256\211\345\205\250.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256/\346\227\245\345\277\227\345\256\211\345\205\250.md" new file mode 100644 index 00000000..63289d80 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\346\225\260\346\215\256\345\256\211\345\205\250\351\205\215\347\275\256/\346\227\245\345\277\227\345\256\211\345\205\250.md" @@ -0,0 +1,238 @@ +# 日志安全 + + +**本文档引用的文件** +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java) +- [ServerLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/ServerLogFilter.java) +- [LoggerUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/LoggerUtils.java) +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + + +## 目录 +1. [引言](#引言) +2. [日志安全架构](#日志安全架构) +3. [敏感信息过滤机制](#敏感信息过滤机制) +4. [日志脱敏配置](#日志脱敏配置) +5. [日志安全最佳实践](#日志安全最佳实践) +6. [结论](#结论) + +## 引言 + +DataVines平台通过多层次的日志安全机制来保护敏感信息,防止密码等机密数据在日志中明文显示。本文档详细说明了DataVines如何通过PasswordFilterUtils和SensitiveDataConverter等组件实现日志脱敏,以及如何配置敏感字段的识别规则和过滤策略。 + +**本节不包含具体文件分析,因此不提供来源** + +## 日志安全架构 + +DataVines的日志安全架构基于Logback框架构建,通过自定义转换器和过滤器实现敏感信息的自动脱敏。系统在日志输出前对消息进行处理,确保敏感数据被正确屏蔽。 + +```mermaid +graph TD +A[日志事件] --> B[SensitiveDataConverter] +B --> C[PasswordFilterUtils] +C --> D[SensitiveLogUtils] +D --> E[脱敏后的日志] +F[server-logback.xml] --> B +G[JobExecutionLogFilter] --> H[日志文件] +I[ServerLogFilter] --> H +``` + +**图表来源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L29-L60) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L25-L76) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L33-L59) + +**本节来源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L1-L60) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L1-L85) + +## 敏感信息过滤机制 + +### PasswordFilterUtils组件 + +PasswordFilterUtils是DataVines中负责处理敏感日志的核心工具类。它通过正则表达式匹配和替换机制,对包含密码等敏感信息的日志消息进行过滤。 + +```mermaid +classDiagram +class PasswordFilterUtils { ++convertPassword(Pattern, String) String ++convertPasswordToNULL(Pattern, String) String +-passwordHandler(Pattern, String, boolean) String +} +class SensitiveDataConverter { ++DATASOURCE_PASSWORD_REGEX String ++DATASOURCE_PASSWORD_REGEX_1 String ++PWD_PATTERN Pattern ++PWD_PATTERN_1 Pattern ++convert(ILoggingEvent) String +} +class SensitiveLogUtils { ++maskDataSourcePwd(String) String +} +SensitiveDataConverter --> PasswordFilterUtils : "使用" +PasswordFilterUtils --> SensitiveLogUtils : "使用" +``` + +**图表来源** +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L25-L76) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L29-L60) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java#L24-L38) + +**本节来源** +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L25-L76) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java#L24-L38) + +### SensitiveDataConverter实现 + +SensitiveDataConverter继承自Logback的MessageConverter,作为日志消息的转换器,在日志输出前对消息内容进行处理。它使用预定义的正则表达式来识别JSON格式中的密码字段。 + +```mermaid +sequenceDiagram +participant Logger as 日志记录器 +participant Converter as SensitiveDataConverter +participant Filter as PasswordFilterUtils +participant Mask as SensitiveLogUtils +Logger->>Converter : 发送日志事件 +Converter->>Converter : 获取格式化消息 +Converter->>Filter : 调用convertPassword +Filter->>Filter : 使用正则表达式匹配 +Filter->>Mask : 调用maskDataSourcePwd +Mask-->>Filter : 返回"******" +Filter-->>Converter : 返回脱敏消息 +Converter-->>Logger : 输出脱敏日志 +``` + +**图表来源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L51-L58) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L32-L41) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java#L30-L36) + +**本节来源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L29-L60) + +## 日志脱敏配置 + +### 敏感字段识别规则 + +DataVines通过正则表达式来识别敏感字段,主要针对JSON格式中的密码字段。系统定义了两种正则表达式模式来匹配不同格式的JSON数据。 + +```mermaid +flowchart TD +A[原始日志消息] --> B{包含"password"字段?} +B --> |是| C[应用正则表达式匹配] +B --> |否| D[保持原样] +C --> E[提取密码值] +E --> F[替换为掩码] +F --> G[返回脱敏消息] +D --> G +``` + +**图表来源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L34-L39) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L59-L74) + +**本节来源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L31-L49) + +### 日志脱敏级别配置 + +通过server-logback.xml配置文件,可以设置日志的脱敏级别和输出格式。DataVines使用自定义的转换规则来启用敏感数据转换器。 + +```xml + +``` + +此配置将"message"关键字映射到SensitiveDataConverter类,使得所有日志消息都会经过该转换器处理。 + +**本节来源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L33-L34) + +### 敏感字段列表配置 + +DataVines目前主要针对数据源配置中的密码字段进行脱敏处理。系统通过以下正则表达式识别敏感字段: + +- `(?<=(\\\"password\\\":\\\")) .*?(?=(\\\"))`:匹配转义引号的JSON格式 +- `(?<=(\"password\": \")) .*?(?=(\"))`:匹配普通引号的JSON格式 + +这些规则在SensitiveDataConverter中作为静态常量定义,确保了敏感信息的一致性处理。 + +**本节来源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L34-L39) + +## 日志安全最佳实践 + +### 审计日志保护 + +DataVines通过JobExecutionLogFilter和ServerLogFilter等过滤器来保护审计日志。这些过滤器基于线程名称来决定是否记录日志,确保只有特定线程的日志被写入文件。 + +```mermaid +classDiagram +class JobExecutionLogFilter { +-level Level ++setLevel(String) void ++decide(ILoggingEvent) FilterReply +} +class ServerLogFilter { +-level Level ++setLevel(String) void ++decide(ILoggingEvent) FilterReply +} +class JobExecutionLogDiscriminator { +-key String +-logBase String ++getDiscriminatingValue(ILoggingEvent) String ++getKey() String ++setKey(String) void ++getLogBase() String ++setLogBase(String) void +} +JobExecutionLogFilter --> JobExecutionLogDiscriminator : "使用" +``` + +**图表来源** +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java#L25-L45) +- [ServerLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/ServerLogFilter.java#L27-L47) +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java#L28-L69) + +**本节来源** +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java#L25-L45) +- [ServerLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/ServerLogFilter.java#L27-L47) + +### 日志访问控制 + +DataVines通过多层机制实现日志访问控制: + +1. **文件权限控制**:日志文件存储在受保护的目录中,只有授权用户才能访问 +2. **线程过滤**:通过自定义过滤器限制日志输出的线程 +3. **日志分离**:使用SiftingAppender根据作业执行唯一ID分离日志文件 + +```mermaid +graph TD +A[日志事件] --> B{线程名称检查} +B --> |以"JobExecutionLogInfo"开头| C[接受] +B --> |否则| D[拒绝] +C --> E{级别>=阈值} +E --> |是| F[写入日志文件] +E --> |否| G[丢弃] +D --> G +``` + +**图表来源** +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java#L39-L43) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L36-L38) + +**本节来源** +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java#L25-L45) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L35-L59) + +## 结论 + +DataVines通过PasswordFilterUtils、SensitiveDataConverter和相关组件构建了一个完整的日志安全体系。该系统能够有效识别和脱敏敏感信息,特别是密码等关键数据,确保日志文件的安全性。通过合理的配置和最佳实践,可以进一步增强日志系统的安全性,保护系统的机密信息不被泄露。 + +**本节不包含具体文件分析,因此不提供来源** \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256/Token\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256/Token\347\256\241\347\220\206.md" new file mode 100644 index 00000000..472ab927 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256/Token\347\256\241\347\220\206.md" @@ -0,0 +1,307 @@ +# Token管理 + + +**本文档引用的文件** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) +- [TokenInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/TokenInfo.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [RefreshToken.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshToken.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细说明DataVines中JWT Token的生成、验证和刷新机制。文档解释了TokenManager类的实现原理,包括Token的创建、解析、验证和刷新流程。同时说明了如何在application.yaml中配置Token的密钥、有效期、刷新策略等参数。文档还提供了代码示例展示Token的生成和验证过程,以及如何通过CheckTokenExist注解保护API接口。最后包含Token安全性最佳实践、常见问题排查和性能优化建议。 + +## 项目结构 +DataVines项目的Token管理功能主要分布在以下几个模块中: +- datavines-core:包含核心的TokenManager类和相关工具 +- datavines-server:包含API控制器、拦截器和认证相关组件 +- datavines-common:包含通用的实体类和工具 + +Token管理的核心功能集中在datavines-core模块的utils包中,通过Spring AOP和拦截器机制与datavines-server模块集成。 + +```mermaid +graph TD +subgraph "datavines-core" +TokenManager[TokenManager] +RefreshToken[RefreshToken] +RefreshTokenAop[RefreshTokenAop] +end +subgraph "datavines-server" +AuthenticationInterceptor[AuthenticationInterceptor] +CheckTokenExist[CheckTokenExist] +AccessTokenController[AccessTokenController] +end +TokenManager --> AuthenticationInterceptor +RefreshTokenAop --> AccessTokenController +CheckTokenExist --> AuthenticationInterceptor +``` + +**图表来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) + +**章节来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +## 核心组件 +DataVines的Token管理核心组件包括TokenManager类、RefreshTokenAop切面、AuthenticationInterceptor拦截器和CheckTokenExist注解。这些组件协同工作,实现了完整的JWT Token生命周期管理。 + +TokenManager类负责Token的生成、解析、验证和刷新等核心功能。它使用JWT标准实现Token的安全管理,并通过Spring的@Value注解从配置文件中读取相关参数。 + +RefreshTokenAop切面用于自动刷新Token,确保用户会话的持续性。AuthenticationInterceptor拦截器负责在请求处理前验证Token的有效性,而CheckTokenExist注解则提供了细粒度的Token存在性检查。 + +**章节来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) + +## 架构概述 +DataVines的Token管理架构采用分层设计,将Token的生成、验证和刷新功能分离,同时通过AOP和拦截器机制实现非侵入式的安全控制。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Controller as "API控制器" +participant AOP as "RefreshTokenAop" +participant TokenManager as "TokenManager" +participant Interceptor as "AuthenticationInterceptor" +Client->>Controller : 发送API请求 +Interceptor->>Interceptor : preHandle() +Interceptor->>TokenManager : 验证Token有效性 +TokenManager-->>Interceptor : 返回验证结果 +Interceptor-->>Controller : 继续处理或返回错误 +Controller->>AOP : 执行业务逻辑 +AOP->>TokenManager : 刷新Token +TokenManager-->>AOP : 返回新Token +AOP-->>Client : 响应包含新Token +``` + +**图表来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +## 详细组件分析 + +### TokenManager分析 +TokenManager是DataVines中负责JWT Token管理的核心类,实现了Token的生成、解析、验证和刷新等关键功能。 + +#### 类图 +```mermaid +classDiagram +class TokenManager { ++String tokenSecret ++Long timeout ++String algorithm ++generateToken(username, password) String ++generateToken(tokenInfo) String ++refreshToken(token) String ++validateToken(token, username, password) boolean ++getUsername(token) String ++getPassword(token) String ++getClaims(token) Claims +} +class DataVinesConstants { ++String TOKEN_PREFIX ++String TOKEN_HEADER_STRING ++String TOKEN_USER_NAME ++String TOKEN_USER_PASSWORD ++String TOKEN_CREATE_TIME +} +class TokenInfo { ++String username ++String password +} +TokenManager --> DataVinesConstants : "使用常量" +TokenManager --> TokenInfo : "作为参数" +TokenManager --> Claims : "JWT声明" +``` + +**图表来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) +- [TokenInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/TokenInfo.java) + +#### Token生成流程 +```mermaid +flowchart TD +Start([开始]) --> CreateClaims["创建声明(claims)"] +CreateClaims --> AddUserInfo["添加用户信息"] +AddUserInfo --> AddCreateTime["添加创建时间"] +AddCreateTime --> GenerateToken["生成Token"] +GenerateToken --> SetSecret["设置密钥"] +SetSecret --> SetAlgorithm["设置算法"] +SetAlgorithm --> SetExpiration["设置过期时间"] +SetExpiration --> Compress["压缩Token"] +Compress --> ReturnToken["返回Token"] +ReturnToken --> End([结束]) +``` + +**图表来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +**章节来源** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +### RefreshToken机制分析 +RefreshToken机制通过AOP切面实现,自动为响应添加刷新后的Token,确保用户会话的持续性。 + +#### AOP流程 +```mermaid +sequenceDiagram +participant Controller as "控制器" +participant AOP as "RefreshTokenAop" +participant TokenManager as "TokenManager" +participant ResultMap as "ResultMap" +Controller->>AOP : 调用被@RefreshToken注解的方法 +AOP->>AOP : pointCut() +AOP->>AOP : doAroundReturningAdvice() +AOP->>Controller : 执行业务逻辑 +Controller-->>AOP : 返回结果 +AOP->>ResultMap : 创建ResultMap +ResultMap->>TokenManager : refreshTokent() +TokenManager-->>ResultMap : 返回新Token +ResultMap-->>AOP : 设置新Token +AOP-->>Controller : 返回包含新Token的响应 +``` + +**图表来源** +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +**章节来源** +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) + +### 认证拦截器分析 +AuthenticationInterceptor负责在请求处理前验证Token的有效性,是安全控制的关键组件。 + +#### 拦截器流程 +```mermaid +flowchart TD +Start([preHandle]) --> CheckAuthIgnore["检查@AuthIgnore注解"] +CheckAuthIgnore --> AuthIgnored{"已忽略?"} +AuthIgnored --> |是| ReturnTrue["返回true"] +AuthIgnored --> |否| GetToken["从请求头获取Token"] +GetToken --> TokenExists{"Token存在?"} +TokenExists --> |否| ThrowException["抛出TOKEN_IS_NULL_ERROR"] +TokenExists --> |是| CheckTokenExist["检查@CheckTokenExist注解"] +CheckTokenExist --> TokenInDB{"Token在数据库?"} +TokenInDB --> |否| ThrowInvalidToken["抛出INVALID_TOKEN"] +TokenInDB --> |是| GetUsername["从Token获取用户名"] +GetUsername --> GetUser["从数据库获取用户"] +GetUser --> UserExists{"用户存在?"} +UserExists --> |否| ThrowInvalidToken +UserExists --> |是| ValidateToken["验证Token有效性"] +ValidateToken --> TokenValid{"Token有效?"} +TokenValid --> |否| ThrowInvalidToken +TokenValid --> |是| SetContext["设置上下文"] +SetContext --> ReturnTrue +ReturnTrue --> End([返回true]) +``` + +**图表来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +**章节来源** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) + +## 依赖分析 +DataVines的Token管理组件之间存在明确的依赖关系,形成了一个完整的安全控制链。 + +```mermaid +graph TD +AccessTokenController --> RefreshToken +AuthenticationInterceptor --> TokenManager +AuthenticationInterceptor --> UserService +AuthenticationInterceptor --> AccessTokenService +RefreshTokenAop --> TokenManager +RefreshTokenAop --> ResultMap +VerificationUtil --> TokenManager +LoginController --> TokenManager +TokenManager --> DataVinesConstants +TokenManager --> TokenInfo +style AccessTokenController fill:#f9f,stroke:#333 +style AuthenticationInterceptor fill:#bbf,stroke:#333 +style RefreshTokenAop fill:#f96,stroke:#333 +style TokenManager fill:#9f9,stroke:#333 +``` + +**图表来源** +- [AccessTokenController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/AccessTokenController.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +**章节来源** +- [AccessTokenController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/AccessTokenController.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +## 性能考虑 +在Token管理方面,DataVines通过以下方式优化性能: + +1. **缓存机制**:虽然当前实现中没有显式的缓存,但可以通过在UserService中添加缓存来减少数据库查询。 +2. **JWT自包含特性**:JWT Token本身包含所有必要信息,避免了每次请求都需要查询数据库。 +3. **异步处理**:Token刷新操作可以在后台异步执行,减少响应时间。 +4. **连接池**:使用HikariCP连接池提高数据库访问效率。 + +建议在高并发场景下考虑引入Redis等缓存系统来存储Token黑名单和用户信息,进一步提升性能。 + +## 故障排除指南 + +### 常见问题及解决方案 +| 问题 | 可能原因 | 解决方案 | +|------|---------|---------| +| Token为空 | 请求头中未包含Authorization字段 | 确保请求头包含"Authorization: Bearer " | +| Token无效 | 密钥不匹配或Token被篡改 | 检查application.yaml中的jwt.token.secret配置 | +| Token过期 | 超过有效期 | 调用刷新Token接口或重新登录 | +| 用户不存在 | 用户名在数据库中不存在 | 检查用户名是否正确或用户是否被删除 | +| 算法不支持 | 配置的算法不受支持 | 检查jwt.token.algorithm配置是否正确 | + +### 配置检查清单 +- [ ] 确认application.yaml中jwt.token.secret已正确配置 +- [ ] 确认jwt.token.timeout设置合理(单位:毫秒) +- [ ] 确认jwt.token.algorithm是JWT支持的算法(如HS256) +- [ ] 确认Token前缀为"Bearer" +- [ ] 确认Token请求头名称为"Authorization" + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +## 结论 +DataVines的Token管理机制基于JWT标准实现,提供了完整的Token生命周期管理功能。通过TokenManager类、AOP切面和拦截器的协同工作,实现了安全、高效的用户认证和授权机制。 + +系统的主要优势包括: +1. **安全性**:使用JWT标准,Token包含签名防止篡改 +2. **可扩展性**:基于Spring框架,易于扩展和定制 +3. **易用性**:通过注解简化了Token管理的使用 +4. **灵活性**:支持多种配置选项,适应不同场景需求 + +建议在生产环境中: +1. 使用强密码作为token.secret +2. 设置合理的token.timeout值 +3. 定期轮换密钥 +4. 监控Token相关的安全事件 +5. 考虑引入分布式缓存提升性能 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256.md" new file mode 100644 index 00000000..7aac5a04 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256.md" @@ -0,0 +1,301 @@ +# 认证配置 + + +**本文档引用的文件** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + + +## 目录 +1. [简介](#简介) +2. [JWT Token管理](#jwt-token管理) +3. [验证码配置](#验证码配置) +4. [登录会话管理](#登录会话管理) +5. [Token过期策略](#token过期策略) +6. [TokenManager实现原理](#tokenmanager实现原理) +7. [认证流程示例](#认证流程示例) +8. [常见问题排查](#常见问题排查) +9. [性能优化建议](#性能优化建议) + +## 简介 +DataVines的用户认证机制基于JWT(JSON Web Token)实现,提供了安全的用户身份验证和授权功能。系统通过TokenManager组件管理JWT Token的生成、验证和刷新,同时集成了Kaptcha验证码系统来增强安全性。本文档详细说明了DataVines的认证配置机制,包括JWT Token的生命周期管理、验证码配置、登录会话处理以及Token过期策略。 + +**Section sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L1-L197) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java#L1-L74) + +## JWT Token管理 + +DataVines使用JWT Token进行用户认证,TokenManager是核心的Token管理组件,负责Token的生成、验证和刷新。JWT Token包含用户信息和创建时间,采用HS256算法进行签名。 + +### Token生成流程 +当用户登录时,系统调用TokenManager的generateToken方法生成JWT Token。Token中包含用户名、密码和创建时间等声明(claims),并使用配置的密钥进行签名。 + +```mermaid +sequenceDiagram +participant 用户 +participant LoginController +participant TokenManager +participant UserService +用户->>LoginController : 提交登录请求 +LoginController->>UserService : 验证用户凭证 +UserService-->>LoginController : 返回用户信息 +LoginController->>TokenManager : 调用generateToken +TokenManager-->>LoginController : 返回JWT Token +LoginController-->>用户 : 返回包含Token的响应 +``` + +**Diagram sources** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L54-L58) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L51-L57) + +### Token验证机制 +系统通过AuthenticationInterceptor拦截器验证每个请求的Token。拦截器从请求头中提取Token,调用TokenManager的validateToken方法验证Token的有效性,包括签名验证和过期时间检查。 + +**Section sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L163-L167) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L96-L98) + +## 验证码配置 + +DataVines集成Kaptcha库实现图形验证码功能,用于注册和登录等敏感操作的安全验证。Kaptcha配置通过KaptchaConfig类进行管理,支持多种自定义选项。 + +### Kaptcha配置参数 +Kaptcha的配置参数通过Spring的@Value注解从配置文件中读取,支持以下可配置项: + +| 配置项 | 默认值 | 说明 | +|--------|-------|------| +| kaptcha.border | yes | 是否显示边框 | +| kaptcha.border.color | 105,179,90 | 边框颜色(RGB) | +| kaptcha.textproducer.font.color | blue | 字体颜色 | +| kaptcha.image.width | 125 | 图片宽度 | +| kaptcha.image.height | 65 | 图片高度 | +| kaptcha.textproducer.font.size | 45 | 字体大小 | +| kaptcha.session.key | code | Session键名 | +| kaptcha.textproducer.char.length | 4 | 验证码字符长度 | +| kaptcha.textproducer.font.names | cmr10 | 字体名称 | + +**Section sources** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java#L29-L55) + +### 验证码生成与验证 +VerificationUtil工具类封装了验证码的生成和验证逻辑。系统生成验证码文本后,使用Kaptcha创建对应的图片,并将验证码文本通过JWT Token加密传输,确保安全性。 + +```mermaid +sequenceDiagram +participant 用户 +participant LoginController +participant VerificationUtil +participant Kaptcha +用户->>LoginController : 请求验证码 +LoginController->>VerificationUtil : 调用createVerificationCodeAndImage +VerificationUtil->>Kaptcha : 生成验证码文本 +Kaptcha-->>VerificationUtil : 返回文本 +VerificationUtil->>Kaptcha : 创建验证码图片 +Kaptcha-->>VerificationUtil : 返回图片 +VerificationUtil->>VerificationUtil : 生成JWT加密的验证码 +VerificationUtil-->>LoginController : 返回图片和加密验证码 +LoginController-->>用户 : 返回验证码数据 +``` + +**Diagram sources** +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java#L52-L58) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L70-L75) + +## 登录会话管理 + +DataVines的登录会话管理采用无状态的JWT Token机制,不依赖服务器端的Session存储。每个请求都必须携带有效的JWT Token进行身份验证。 + +### Token刷新机制 +系统通过RefreshTokenAop切面实现Token自动刷新功能。当带有@RefreshToken注解的控制器方法被调用时,AOP会自动更新Token的创建时间,延长其有效期。 + +```mermaid +classDiagram +class RefreshToken { ++@Target({ElementType.TYPE}) ++@Retention(RetentionPolicy.RUNTIME) +} +class RefreshTokenAop { +-TokenManager tokenManager ++doAroundReturningAdvice(ProceedingJoinPoint) +} +class TokenManager { ++generateToken(String, String) ++refreshToken(String) ++validateToken(String, String, String) +} +RefreshTokenAop --> TokenManager : "使用" +RefreshTokenAop --> RefreshToken : "监听" +``` + +**Diagram sources** +- [RefreshToken.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshToken.java#L24-L27) +- [RefreshTokenAop.java](file://datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java#L39-L59) + +### 认证拦截器 +AuthenticationInterceptor是核心的认证拦截器,负责处理所有API请求的认证逻辑。拦截器通过以下步骤验证请求: + +1. 检查方法是否标记为@AuthIgnore(无需认证) +2. 从请求头或参数中提取Token +3. 验证Token的有效性 +4. 设置当前登录用户上下文 + +**Section sources** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L54-L98) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java#L44-L48) + +## Token过期策略 + +DataVines实现了灵活的Token过期策略,通过配置文件和代码双重控制Token的有效期。 + +### 配置参数 +Token的过期策略通过以下配置参数控制: + +- **jwt.token.secret**: Token签名密钥,默认值为"asdqwe" +- **jwt.token.timeout**: Token超时时间(毫秒),默认值为8640000(2.4小时) +- **jwt.token.algorithm**: 签名算法,默认值为"HS256" + +这些参数可以在application.yaml文件中进行配置: + +```yaml +jwt: + token: + secret: your-secret-key + timeout: 7200000 # 2小时 + algorithm: HS256 +``` + +**Section sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L42-L49) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L1-L96) + +### 过期时间验证 +TokenManager通过isExpired方法检查Token是否过期。系统在每次验证Token时都会检查其过期时间,确保只有有效的Token才能通过认证。 + +```mermaid +flowchart TD +Start([开始验证Token]) --> GetExpiration["获取Token过期时间"] +GetExpiration --> CheckNull{"过期时间为空?"} +CheckNull --> |是| ReturnInvalid["返回无效Token"] +CheckNull --> |否| GetCurrentTime["获取当前时间"] +GetCurrentTime --> Compare["比较当前时间与过期时间"] +Compare --> IsExpired{"已过期?"} +IsExpired --> |是| ReturnExpired["返回过期Token"] +IsExpired --> |否| ReturnValid["返回有效Token"] +ReturnInvalid --> End([结束]) +ReturnExpired --> End +ReturnValid --> End +``` + +**Diagram sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L191-L194) + +## TokenManager实现原理 + +TokenManager是DataVines认证系统的核心组件,基于Spring框架和JWT标准实现。其主要功能包括Token生成、解析、验证和刷新。 + +### 核心方法 +TokenManager提供了以下核心方法: + +- **generateToken**: 生成新的JWT Token +- **getClaims**: 解析Token获取声明信息 +- **refreshToken**: 刷新Token有效期 +- **validateToken**: 验证Token的有效性 +- **getUsername**: 从Token中提取用户名 +- **getPassword**: 从Token中提取密码 + +### 依赖关系 +TokenManager依赖于Spring的@Value注解注入配置参数,并使用io.jsonwebtoken库进行JWT操作。系统通过@Component注解将其注册为Spring Bean,便于其他组件注入使用。 + +**Section sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L40-L196) + +## 认证流程示例 + +以下是一个完整的用户登录认证流程示例: + +### 登录流程 +1. 用户访问登录页面 +2. 系统生成验证码并显示 +3. 用户输入用户名、密码和验证码 +4. 前端将数据提交到/login API +5. 后端验证验证码和用户凭证 +6. 生成JWT Token并返回给客户端 + +### API调用流程 +1. 客户端在请求头中添加Authorization字段 +2. 服务器拦截请求并验证Token +3. 执行业务逻辑 +4. 返回响应结果 + +```mermaid +sequenceDiagram +participant Client +participant Server +participant Database +Client->>Server : GET /refreshVerificationCode +Server->>Server : 生成验证码图片和JWT +Server-->>Client : 返回验证码数据 +Client->>Server : POST /login {user, pwd, captcha} +Server->>Server : 验证验证码JWT +Server->>Database : 查询用户信息 +Database-->>Server : 返回用户数据 +Server->>Server : 生成JWT Token +Server-->>Client : 返回Token和用户信息 +Client->>Server : GET /api/data Authorization : Bearer +Server->>Server : 验证Token有效性 +Server->>Database : 查询数据 +Database-->>Server : 返回查询结果 +Server-->>Client : 返回数据 +``` + +**Diagram sources** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java#L54-L75) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L54-L98) + +## 常见问题排查 + +### Token相关问题 +- **Token无效**: 检查Token签名密钥是否匹配,确认算法配置正确 +- **Token过期**: 检查jwt.token.timeout配置,确认客户端时间同步 +- **Token解析失败**: 确认Token格式正确,检查是否包含Bearer前缀 + +### 验证码问题 +- **验证码不显示**: 检查Kaptcha配置,确认图片生成参数正确 +- **验证码验证失败**: 确认JWT加密的验证码未过期(默认5分钟) +- **验证码刷新异常**: 检查VerificationUtil的buildJwtVerification方法 + +### 配置问题 +- **配置不生效**: 确认application.yaml中的配置路径正确 +- **环境变量覆盖**: 检查是否有环境变量覆盖了配置文件的值 +- **配置文件加载顺序**: 确认Spring Profile的激活状态 + +**Section sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L132-L152) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java#L60-L75) + +## 性能优化建议 + +### Token管理优化 +- **合理设置Token有效期**: 根据业务需求平衡安全性和用户体验 +- **使用缓存**: 对频繁验证的Token进行缓存,减少JWT解析开销 +- **批量操作**: 在需要多次验证的场景中,考虑批量验证机制 + +### 验证码优化 +- **调整验证码复杂度**: 根据安全需求调整字符长度和字体复杂度 +- **异步生成**: 对于高并发场景,考虑异步生成验证码图片 +- **CDN加速**: 将验证码图片托管到CDN,提高加载速度 + +### 系统配置优化 +- **监控Token使用情况**: 记录Token生成和验证的日志,便于问题排查 +- **定期轮换密钥**: 定期更新jwt.token.secret以增强安全性 +- **压力测试**: 对认证系统进行压力测试,确保高并发下的稳定性 + +**Section sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L42-L49) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java#L29-L55) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256/\351\252\214\350\257\201\347\240\201\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256/\351\252\214\350\257\201\347\240\201\351\205\215\347\275\256.md" new file mode 100644 index 00000000..1e6cf47f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\345\256\211\345\205\250\351\205\215\347\275\256/\350\256\244\350\257\201\351\205\215\347\275\256/\351\252\214\350\257\201\347\240\201\351\205\215\347\275\256.md" @@ -0,0 +1,261 @@ +# 验证码配置 + + +**本文档引用的文件** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [KaptchaResp.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/KaptchaResp.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [useVerificationCode/index.tsx](file://datavines-ui/src/hooks/useVerificationCode/index.tsx) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +DataVines系统集成了Kaptcha验证码功能,用于增强系统的安全性,特别是在用户注册和登录等关键操作中。本文档详细说明了Kaptcha验证码的配置和使用方法,包括验证码的视觉属性配置、长度、有效期、存储策略以及在登录接口中的集成方式。通过application.yaml文件中的配置项,可以灵活地自定义验证码的外观和行为。验证码的验证过程结合了JWT令牌机制,确保了验证码的安全性和时效性。前端通过调用后端API获取验证码图片和JWT令牌,并在用户提交表单时进行验证。整个流程设计考虑了安全性、性能和用户体验,为系统提供了可靠的防自动化攻击保护。 + +## 项目结构 +DataVines项目的验证码功能主要集中在datavines-server模块中,相关的配置和工具类位于特定的包路径下。前端实现位于datavines-ui模块中,通过React Hooks进行封装和调用。整体结构体现了前后端分离的设计模式,后端提供RESTful API接口,前端通过HTTP请求与后端交互。 + +```mermaid +graph TD +subgraph "后端模块" +datavines-server[datavines-server] +KaptchaConfig[KaptchaConfig.java] +VerificationUtil[VerificationUtil.java] +LoginController[LoginController.java] +end +subgraph "前端模块" +datavines-ui[datavines-ui] +useVerificationCode[useVerificationCode/index.tsx] +end +subgraph "配置文件" +application-yaml[application.yaml] +end +datavines-server --> KaptchaConfig +datavines-server --> VerificationUtil +datavines-server --> LoginController +datavines-ui --> useVerificationCode +application-yaml --> KaptchaConfig +LoginController < --> useVerificationCode +``` + +**图表来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [useVerificationCode/index.tsx](file://datavines-ui/src/hooks/useVerificationCode/index.tsx) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +**章节来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [useVerificationCode/index.tsx](file://datavines-ui/src/hooks/useVerificationCode/index.tsx) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 核心组件 +DataVines的验证码系统由多个核心组件构成,包括KaptchaConfig配置类、VerificationUtil工具类、LoginController控制器以及前端的useVerificationCode Hook。KaptchaConfig类负责初始化和配置Kaptcha验证码生成器,通过Spring的@Value注解从application.yaml文件中读取配置参数。VerificationUtil类提供了生成验证码图片和验证用户输入的核心方法,利用Kaptcha的API生成文本和图片,并通过JWT令牌机制确保验证码的安全传输和验证。LoginController暴露了获取验证码和用户注册的RESTful接口,其中注册接口会调用VerificationUtil进行验证码验证。前端的useVerificationCode Hook封装了获取验证码的逻辑,通过HTTP请求调用后端接口,并在组件挂载时自动获取初始验证码。这些组件协同工作,形成了一个完整的验证码解决方案。 + +**章节来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [useVerificationCode/index.tsx](file://datavines-ui/src/hooks/useVerificationCode/index.tsx) + +## 架构概述 +DataVines验证码系统的架构采用了典型的前后端分离模式,后端基于Spring Boot框架提供RESTful API,前端基于React框架进行UI渲染和交互。验证码的生成和验证逻辑完全在后端实现,前端仅负责展示和提交。系统通过JWT令牌机制在客户端和服务器之间安全地传递验证码信息,避免了在服务器端存储验证码带来的状态管理复杂性。这种无状态的设计提高了系统的可扩展性和可靠性。 + +```mermaid +sequenceDiagram +participant 前端 as 前端(UI) +participant 后端 as 后端(Server) +participant Kaptcha as Kaptcha库 +前端->>后端 : GET /refreshVerificationCode +后端->>Kaptcha : 生成验证码文本 +Kaptcha-->>后端 : 返回文本 +后端->>Kaptcha : 生成验证码图片 +Kaptcha-->>后端 : 返回图片 +后端->>后端 : 创建JWT令牌 +后端-->>前端 : 返回图片Base64和JWT +前端->>用户 : 显示验证码图片 +用户->>前端 : 输入验证码并提交 +前端->>后端 : POST /register (含验证码和JWT) +后端->>后端 : 验证JWT有效性 +后端->>后端 : 比对验证码 +后端-->>前端 : 返回注册结果 +``` + +**图表来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [useVerificationCode/index.tsx](file://datavines-ui/src/hooks/useVerificationCode/index.tsx) + +## 详细组件分析 + +### KaptchaConfig配置类分析 +KaptchaConfig类是验证码系统的核心配置组件,它通过Spring的@Configuration注解声明为一个配置类,并使用@Bean注解定义了一个DefaultKaptcha的Bean。该类通过@Value注解从application.yaml文件中注入各种配置参数,然后将这些参数设置到Kaptcha的Properties对象中,最终创建并返回一个配置好的DefaultKaptcha实例。这种设计使得验证码的配置完全外部化,无需修改代码即可调整验证码的外观和行为。 + +```mermaid +classDiagram +class KaptchaConfig { ++String kaptchaBorder ++String kaptchaBorderColor ++String kaptchaTextproducerFontColor ++String kaptchaImageWidth ++String kaptchaImageHeight ++String kaptchaTextproducerFontSize ++String kaptchaSessionKey ++String getKaptchaTextproducerCharLength ++String kaptchaTextproducerFontNames ++DefaultKaptcha captchaProducer() +} +class DefaultKaptcha { ++void setConfig(Config config) ++String createText() ++BufferedImage createImage(String text) +} +class Config { ++Config(Properties properties) +} +KaptchaConfig --> DefaultKaptcha : "创建" +KaptchaConfig --> Config : "使用" +DefaultKaptcha --> Config : "依赖" +``` + +**图表来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) + +**章节来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) + +### VerificationUtil工具类分析 +VerificationUtil类是验证码系统的核心工具类,提供了生成验证码图片和验证用户输入的静态方法。该类在静态代码块中通过SpringApplicationContext获取DefaultKaptcha和TokenManager的实例,确保了在整个应用生命周期内使用同一个验证码生成器和令牌管理器。createVerificationCodeAndImage方法生成验证码文本,然后调用buildImageByte64方法将文本转换为Base64编码的图片数据,同时调用buildJwtVerification方法创建包含验证码信息的JWT令牌。validVerificationCode方法则负责验证用户提交的验证码是否与JWT令牌中的信息匹配,并检查令牌是否过期。 + +```mermaid +flowchart TD +Start([生成验证码]) --> CreateText["生成验证码文本"] +CreateText --> BuildImage["生成图片并转Base64"] +BuildImage --> BuildJWT["创建JWT令牌"] +BuildJWT --> Return["返回图片和JWT"] +ValidateStart([验证验证码]) --> ParseJWT["解析JWT令牌"] +ParseJWT --> CheckExpired["检查是否过期"] +CheckExpired --> |是| ThrowExpired["抛出过期异常"] +CheckExpired --> |否| CompareCode["比对验证码"] +CompareCode --> |匹配| ReturnSuccess["验证成功"] +CompareCode --> |不匹配| ThrowInvalid["抛出无效异常"] +ThrowExpired --> End([结束]) +ReturnSuccess --> End +ThrowInvalid --> End +``` + +**图表来源** +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) + +**章节来源** +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) + +### LoginController控制器分析 +LoginController类是验证码系统的API入口,它暴露了两个关键接口:/refreshVerificationCode用于获取新的验证码,/register用于用户注册。refreshVerificationCode接口调用VerificationUtil.createVerificationCodeAndImage方法生成验证码,并将结果封装在ResultMap中返回。register接口在处理用户注册请求时,首先调用VerificationUtil.validVerificationCode方法验证用户提交的验证码,只有验证通过才会继续执行注册逻辑。这种设计确保了注册操作的安全性,防止了自动化脚本的滥用。 + +```mermaid +sequenceDiagram +participant 前端 as 前端 +participant 控制器 as LoginController +participant 工具类 as VerificationUtil +participant 服务 as UserService +前端->>控制器 : GET /refreshVerificationCode +控制器->>工具类 : createVerificationCodeAndImage() +工具类-->>控制器 : 返回KaptchaResp +控制器-->>前端 : 返回ResultMap +前端->>控制器 : POST /register +控制器->>工具类 : validVerificationCode() +工具类-->>控制器 : 验证结果 +alt 验证成功 +控制器->>服务 : userService.register() +服务-->>控制器 : 注册结果 +控制器-->>前端 : 返回成功 +else 验证失败 +控制器-->>前端 : 返回错误 +end +``` + +**图表来源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) + +**章节来源** +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) + +### 前端useVerificationCode Hook分析 +useVerificationCode是一个React Hook,用于在前端组件中管理验证码的状态和获取逻辑。它使用useState来存储验证码的图片数据和JWT令牌,使用useRef来保持对当前验证码的引用。getImage函数通过$http.get请求调用后端的/refreshVerificationCode接口获取新的验证码,并更新状态。useMount Hook确保在组件挂载时自动获取初始验证码。返回的RenderImage是一个不可变的函数组件,用于渲染验证码图片,并在点击时刷新验证码,实现了良好的用户体验。 + +```mermaid +flowchart TD +A[组件挂载] --> B[调用useMount] +B --> C[执行getImage] +C --> D[发送HTTP请求] +D --> E[后端返回验证码] +E --> F[更新状态] +F --> G[渲染图片] +G --> H[用户点击图片] +H --> C +``` + +**图表来源** +- [useVerificationCode/index.tsx](file://datavines-ui/src/hooks/useVerificationCode/index.tsx) + +**章节来源** +- [useVerificationCode/index.tsx](file://datavines-ui/src/hooks/useVerificationCode/index.tsx) + +## 依赖分析 +DataVines验证码系统的组件之间存在清晰的依赖关系。后端的KaptchaConfig依赖于Spring框架的配置机制和Kaptcha库;VerificationUtil依赖于KaptchaConfig创建的DefaultKaptcha实例和TokenManager进行JWT操作;LoginController依赖于VerificationUtil进行验证码验证和UserService处理业务逻辑。前端的useVerificationCode依赖于$http服务进行HTTP通信。整个系统的依赖关系简单明了,各组件职责单一,易于维护和扩展。 + +```mermaid +graph TD +KaptchaConfig --> Spring +KaptchaConfig --> Kaptcha +VerificationUtil --> KaptchaConfig +VerificationUtil --> TokenManager +LoginController --> VerificationUtil +LoginController --> UserService +useVerificationCode --> http +http --> LoginController +``` + +**图表来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [useVerificationCode/index.tsx](file://datavines-ui/src/hooks/useVerificationCode/index.tsx) + +**章节来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) +- [useVerificationCode/index.tsx](file://datavines-ui/src/hooks/useVerificationCode/index.tsx) + +## 性能考虑 +DataVines验证码系统在设计时充分考虑了性能因素。首先,验证码的生成和验证都是内存操作,不涉及数据库访问,保证了高并发下的响应速度。其次,通过JWT令牌机制实现了无状态验证,避免了在服务器端存储验证码带来的内存开销和分布式环境下的会话同步问题。验证码的有效期设置为5分钟(300000毫秒),平衡了安全性和用户体验。前端通过点击刷新验证码,减少了不必要的请求。整体设计确保了系统在高负载下仍能稳定运行。 + +## 故障排除指南 +当验证码功能出现问题时,可以按照以下步骤进行排查:首先检查application.yaml中的kaptcha配置项是否正确;其次确认KaptchaConfig类是否被Spring正确加载;然后检查VerificationUtil中的静态代码块是否成功获取了DefaultKaptcha和TokenManager的实例;最后验证LoginController的接口是否能正常访问。常见的错误包括配置项拼写错误、依赖库缺失、JWT密钥不匹配等。通过查看日志文件可以快速定位问题根源。 + +**章节来源** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [LoginController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java) + +## 结论 +DataVines的验证码系统通过Kaptcha库和JWT令牌的结合,实现了一个安全、高效、可配置的验证码解决方案。系统设计合理,组件职责清晰,前后端分离明确。通过外部化配置,管理员可以轻松调整验证码的外观和行为。无状态的验证机制提高了系统的可扩展性和可靠性。整体方案为DataVines系统提供了有效的安全防护,防止了自动化攻击,同时保证了良好的用户体验。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Flink\346\211\247\350\241\214\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Flink\346\211\247\350\241\214\351\205\215\347\275\256.md" new file mode 100644 index 00000000..58534dcd --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Flink\346\211\247\350\241\214\351\205\215\347\275\256.md" @@ -0,0 +1,370 @@ +# Flink执行配置 + + +**本文档引用的文件** +- [BaseFlinkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-config\src\main\java\io\datavines\engine\flink\config\BaseFlinkConfigurationBuilder.java) +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java) +- [FlinkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkParameters.java) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java) +- [FlinkRuntimeEnvironment.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-api\src\main\java\io\datavines\engine\flink\api\FlinkRuntimeEnvironment.java) +- [FlinkDataVinesBootstrap.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-core\src\main\java\io\datavines\engine\flink\core\FlinkDataVinesBootstrap.java) +- [FlinkConfiguration.tsx](file://datavines-ui\src\view\Main\Config\FlinkConfiguration.tsx) + + +## 目录 +1. [Flink配置构建器](#flink配置构建器) +2. [Flink作业参数设置](#flink作业参数设置) +3. [Flink集群连接配置](#flink集群连接配置) +4. [FlinkEngineExecutor作业提交与管理](#flinkengineexecutor作业提交与管理) +5. [Flink执行模式与性能调优](#flink执行模式与性能调优) +6. [常见问题解决方案](#常见问题解决方案) + +## Flink配置构建器 + +DataVines通过`BaseFlinkConfigurationBuilder`类实现Flink执行配置的构建。该类继承自`BaseJobConfigurationBuilder`,负责构建Flink作业所需的环境配置、数据源配置和结果输出配置。 + +`BaseFlinkConfigurationBuilder`的主要功能包括: +- 构建环境配置(EnvConfig),设置引擎类型 +- 构建数据源配置(SourceConfig),处理连接参数和SQL语句 +- 构建结果输出配置(SinkConfig),定义验证结果的存储方式 +- 处理多数据源连接,支持源表和目标表的对比验证 + +具体实现中,该构建器通过插件加载机制(PluginLoader)动态加载不同类型的连接器工厂(ConnectorFactory)和SQL指标(SqlMetric),并根据配置参数生成相应的Flink作业配置。 + +**Section sources** +- [BaseFlinkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-config\src\main\java\io\datavines\engine\flink\config\BaseFlinkConfigurationBuilder.java#L47-L330) + +## Flink作业参数设置 + +Flink作业的参数通过`FlinkParameters`类进行定义和管理。该类包含了Flink作业执行所需的各种配置参数: + +```java +@Data +public class FlinkParameters { + private String mainJar; + private String mainClass; + private String deployMode; + private String taskManagerCount; + private String taskManagerMemory; + private String jobManagerMemory; + private String mainArgs; + private String yarnQueue; + private String jobName; + private int parallelism = 1; + private String flinkOthers; + private String jars; + private String tags; +} +``` + +关键参数说明: +- **deployMode**: 部署模式,支持local、yarn-session、yarn-per-job、yarn-application +- **parallelism**: 作业并行度,默认为1 +- **taskManagerMemory**: TaskManager内存大小 +- **jobManagerMemory**: JobManager内存大小 +- **yarnQueue**: YARN队列名称 +- **jobName**: 作业名称 +- **mainArgs**: 主程序参数,以Base64编码传递作业配置 + +这些参数通过`FlinkArgsUtils.buildArgs()`方法转换为实际的Flink命令行参数。 + +**Section sources** +- [FlinkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkParameters.java#L22-L49) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java#L24-L124) + +## Flink集群连接配置 + +Flink集群的连接配置主要通过前端UI和后端参数传递实现。前端配置界面提供了直观的参数输入表单,后端通过参数解析和命令构建实现与Flink集群的连接。 + +### 前端配置参数 + +前端`FlinkConfiguration.tsx`组件定义了Flink配置的UI表单,包含以下主要参数: + +```typescript +const schema: IFormRender = { + meta: [ + { + label: '部署模式', + name: 'deployMode', + widget: ( + + ), + }, + { + label: 'Flink主目录', + name: 'flinkHome', + widget: , + }, + { + label: 'JobManager内存', + name: 'jobmanagerMemory', + widget: , + }, + { + label: 'TaskManager内存', + name: 'taskmanagerMemory', + widget: , + }, + ], +}; +``` + +### 后端命令构建 + +后端通过`FlinkArgsUtils.buildArgs()`方法将配置参数转换为Flink命令行参数。不同部署模式对应的命令如下: + +```mermaid +flowchart TD +A[开始] --> B{部署模式} +B --> |local| C[flink run] +B --> |yarn-session| D[flink run -t yarn-session] +B --> |yarn-per-job| E[flink run -t yarn-per-job --detached] +B --> |yarn-application| F[flink run-application -t yarn-application] +C --> G[添加并行度参数] +D --> G +E --> G +F --> G +G --> H[添加内存配置] +H --> I[添加作业名称] +I --> J[添加YARN队列] +J --> K[添加主类和JAR] +K --> L[构建完整命令] +L --> M[结束] +``` + +**Diagram sources** +- [FlinkConfiguration.tsx](file://datavines-ui\src\view\Main\Config\FlinkConfiguration.tsx#L23-L78) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java#L44-L64) + +**Section sources** +- [FlinkConfiguration.tsx](file://datavines-ui\src\view\Main\Config\FlinkConfiguration.tsx#L1-L84) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java#L35-L124) + +## FlinkEngineExecutor作业提交与管理 + +`FlinkEngineExecutor`是DataVines中负责Flink作业提交和管理的核心类。它继承自`AbstractYarnEngineExecutor`,实现了Flink作业的初始化、执行、监控和取消功能。 + +### 类结构与主要组件 + +```mermaid +classDiagram +class FlinkEngineExecutor { +-Configurations configurations +-JobExecutionRequest jobExecutionRequest +-Logger logger +-ProcessResult processResult +-BaseCommandProcess shellCommandProcess +-boolean cancel ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++buildCommand() ++getProcessResult() ++cancel() ++logHandle(String[]) +} +class AbstractYarnEngineExecutor { ++cancel() ++killYarnApplication() +} +FlinkEngineExecutor --> AbstractYarnEngineExecutor : "继承" +FlinkEngineExecutor --> BaseCommandProcess : "使用" +FlinkEngineExecutor --> FlinkArgsUtils : "使用" +``` + +**Diagram sources** +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java#L38-L182) + +### 作业提交流程 + +Flink作业的提交流程通过`execute()`方法实现,主要步骤如下: + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Executor as "FlinkEngineExecutor" +participant Shell as "ShellCommandProcess" +participant Flink as "Flink集群" +Client->>Executor : init(初始化) +Executor->>Executor : 设置日志线程名 +Executor->>Executor : 初始化组件 +Client->>Executor : execute(执行) +Executor->>Executor : buildCommand(构建命令) +Executor->>Shell : run(执行命令) +Shell->>Flink : 提交Flink作业 +Flink-->>Shell : 返回执行结果 +Shell-->>Executor : processResult +Executor->>Client : 返回执行结果 +alt 作业取消 +Client->>Executor : cancel() +Executor->>Executor : killYarnApplication() +Executor->>Shell : cancel() +end +``` + +**Diagram sources** +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java#L71-L82) + +### 命令构建逻辑 + +`buildCommand()`方法负责构建完整的Flink命令行,其核心逻辑包括: + +1. 解析Flink参数(FlinkParameters) +2. 设置主JAR包路径 +3. 编码作业配置参数(Base64编码) +4. 设置主类名称 +5. 生成唯一标签 +6. 调用FlinkArgsUtils构建命令参数 +7. 组装完整命令字符串 + +```java +@Override +protected String buildCommand() { + FlinkParameters flinkParameters = JSONUtils.parseObject(jobExecutionRequest.getEngineParameter(), FlinkParameters.class); + + String basePath = System.getProperty("user.dir").replace(File.separator + "bin", File.separator + "libs"); + flinkParameters.setMainJar(basePath + File.separator + configurations.getString("data.quality.flink.jar.name")); + + DataVinesJobConfig configuration = JSONUtils.parseObject(jobExecutionRequest.getApplicationParameter(), DataVinesJobConfig.class); + flinkParameters.setMainArgs("\"" + Base64.getEncoder().encodeToString(JSONUtils.toJsonString(configuration).getBytes()) + "\""); + + flinkParameters.setMainClass("io.datavines.engine.flink.core.FlinkDataVinesBootstrap"); + flinkParameters.setTags(jobExecutionRequest.getJobExecutionUniqueId()); + + List args = new ArrayList<>(); + args.add(FLINK_COMMAND); + args.addAll(FlinkArgsUtils.buildArgs(flinkParameters)); + + return String.join(" ", args); +} +``` + +**Section sources** +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java#L84-L125) + +## Flink执行模式与性能调优 + +### Flink执行模式 + +DataVines支持多种Flink执行模式,每种模式适用于不同的应用场景: + +| 执行模式 | 描述 | 适用场景 | +|--------|------|--------| +| local | 本地模式,在本地JVM中运行 | 开发测试、小规模数据验证 | +| yarn-session | YARN会话模式,复用已有的YARN会话 | 频繁提交的小作业,快速响应 | +| yarn-per-job | YARN单作业模式,每个作业独立的YARN应用 | 生产环境,资源隔离 | +| yarn-application | YARN应用模式,Flink作为YARN应用运行 | 长期运行的流处理作业 | + +### 并行度设置 + +并行度(parallelism)是影响Flink作业性能的关键参数。DataVines通过`FlinkParameters.parallelism`属性进行设置: + +- **默认值**: 1 +- **推荐设置**: 根据数据量和集群资源调整 +- **最佳实践**: + - 批处理作业:设置为CPU核心数的2-4倍 + - 流处理作业:根据数据吞吐量动态调整 + - 资源充足时,适当提高并行度以提升处理速度 + +### Checkpoint配置 + +虽然代码中未直接体现Checkpoint配置,但可以通过`flinkOthers`参数传递自定义的Flink配置: + +```java +// 通过flinkOthers参数设置Checkpoint相关配置 +flinkParameters.setFlinkOthers("--conf state.checkpoints.dir=hdfs://namenode:8020/flink/checkpoints " + + "--conf state.savepoints.dir=hdfs://namenode:8020/flink/savepoints " + + "--conf state.checkpoint.interval=5min"); +``` + +### StateBackend配置 + +StateBackend配置同样可以通过`flinkOthers`参数进行设置: + +```java +// 设置StateBackend为RocksDB +flinkParameters.setFlinkOthers("--conf state.backend=rocksdb " + + "--conf state.backend.rocksdb.localdir=/tmp/flink/rocksdb"); +``` + +### 性能调优建议 + +1. **内存配置优化**: + - 合理设置JobManager和TaskManager内存 + - 根据作业复杂度调整堆内存和堆外内存比例 + +2. **资源分配策略**: + - YARN模式下合理分配队列资源 + - 避免资源过度分配导致的浪费 + +3. **网络缓冲区调优**: + - 根据网络环境调整网络缓冲区大小 + - 平衡延迟和吞吐量 + +4. **序列化优化**: + - 使用高效的序列化框架 + - 减少序列化开销 + +**Section sources** +- [FlinkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkParameters.java#L42-L44) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java#L85-L91) + +## 常见问题解决方案 + +### 作业提交失败 + +**问题现象**: Flink作业提交失败,无具体错误信息 + +**解决方案**: +1. 检查Flink_HOME环境变量是否正确设置 +2. 确认Flink集群处于正常运行状态 +3. 验证YARN队列资源是否充足 +4. 检查作业JAR包路径是否正确 + +### 内存不足错误 + +**问题现象**: TaskManager或JobManager内存溢出 + +**解决方案**: +1. 增加`jobManagerMemory`和`taskManagerMemory`配置值 +2. 优化作业逻辑,减少状态大小 +3. 调整并行度,平衡资源使用 +4. 考虑使用RocksDB作为StateBackend + +### 作业卡住或无响应 + +**问题现象**: 作业长时间运行无进展 + +**解决方案**: +1. 检查数据源连接是否正常 +2. 验证SQL查询是否过于复杂 +3. 增加Checkpoint间隔,减少检查点开销 +4. 调整网络缓冲区大小 + +### YARN应用无法启动 + +**问题现象**: YARN应用提交后立即失败 + +**解决方案**: +1. 检查YARN队列权限 +2. 确认集群资源是否充足 +3. 验证用户代理设置 +4. 检查Flink版本与Hadoop版本兼容性 + +### 数据源连接问题 + +**问题现象**: 无法连接到数据源 + +**解决方案**: +1. 验证连接参数(URL、用户名、密码) +2. 检查网络连通性 +3. 确认数据库驱动是否正确 +4. 验证数据库连接池配置 + +**Section sources** +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java#L78-L81) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java#L74-L83) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256/Spark Livy\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256/Spark Livy\351\205\215\347\275\256.md" new file mode 100644 index 00000000..ae7169bd --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256/Spark Livy\351\205\215\347\275\256.md" @@ -0,0 +1,396 @@ +# Spark Livy配置 + + +**本文档引用的文件** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [LivySparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\LivySparkParameters.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\SparkParameters.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java) +- [ResourceSchedulePlatformType.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\ResourceSchedulePlatformType.java) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) + + +## 目录 +1. [简介](#简介) +2. [LivyEngineExecutor工作机制](#livyengineexecutor工作机制) +3. [Livy服务器连接配置](#livy服务器连接配置) +4. [会话管理与资源调度平台](#会话管理与资源调度平台) +5. [Spark参数配置](#spark参数配置) +6. [Livy状态监控](#livy状态监控) +7. [配置示例](#配置示例) +8. [性能优化建议](#性能优化建议) +9. [故障排查指南](#故障排查指南) + +## 简介 + +DataVines通过Livy引擎提交Spark任务,实现对Spark作业的远程提交和管理。Livy作为REST服务接口,允许用户通过HTTP请求与Spark集群交互,提交作业、监控状态和获取结果。本文档详细说明了在DataVines中配置和使用Livy提交Spark任务的方法,涵盖LivyEngineExecutor的工作机制、连接配置、会话管理、资源调度平台设置、状态监控以及相关参数配置。 + +## LivyEngineExecutor工作机制 + +LivyEngineExecutor是DataVines中负责通过Livy提交Spark任务的核心执行器。它继承自AbstractLivyEngineExecutor,实现了EngineExecutor接口,负责构建Livy REST API请求、提交任务、监控执行状态和处理结果。 + +LivyEngineExecutor的主要工作流程如下: +1. 初始化时设置日志记录器和任务请求信息 +2. 通过buildCommand()方法构建Livy REST API请求体 +3. 调用LivyCommandProcess向Livy服务器提交任务 +4. 监控任务执行状态直到完成或失败 +5. 返回执行结果 + +**Section sources** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L42-L236) + +## Livy服务器连接配置 + +要通过Livy提交Spark任务,需要正确配置Livy服务器的连接信息。主要配置参数包括Livy服务器地址、Kerberos认证设置等。 + +关键配置项: +- `livy.uri`:Livy服务器的REST API地址,格式为`http://:/batches` +- `livy.need.kerberos`:是否需要Kerberos认证,值为"true"或"false" +- `livy.server.auth.kerberos.principal`:Kerberos认证的主体名称 +- `livy.server.auth.kerberos.keytab`:Kerberos密钥表文件路径 + +当Livy服务器启用了Kerberos认证时,需要提供相应的principal和keytab文件来完成认证。LivyTaskSubmitHelper类负责处理与Livy服务器的HTTP通信,根据配置决定是否使用KerberosRestTemplate进行认证。 + +```mermaid +sequenceDiagram +participant DataVines as DataVines系统 +participant LivyExecutor as LivyEngineExecutor +participant LivyHelper as LivyTaskSubmitHelper +participant LivyServer as Livy服务器 +DataVines->>LivyExecutor : 提交任务请求 +LivyExecutor->>LivyExecutor : 构建Livy命令 +LivyExecutor->>LivyHelper : 调用postToLivy +alt 需要Kerberos认证 +LivyHelper->>LivyServer : 使用KerberosRestTemplate发送POST请求 +else 不需要Kerberos认证 +LivyHelper->>LivyServer : 使用RestTemplate发送POST请求 +end +LivyServer-->>LivyHelper : 返回会话ID和状态 +LivyHelper-->>LivyExecutor : 返回结果 +LivyExecutor->>LivyExecutor : 监控任务状态 +LivyExecutor-->>DataVines : 返回执行结果 +``` + +**Diagram sources** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L42-L236) + +**Section sources** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) + +## 会话管理与资源调度平台 + +Livy通过会话(Session)机制管理Spark任务。每个提交的任务都会创建一个独立的会话,Livy服务器负责维护会话状态并提供REST API进行状态查询和管理。 + +### 会话生命周期管理 + +Livy支持多种会话状态,包括: +- NOT_STARTED:会话未开始 +- STARTING:会话正在启动 +- IDLE:会话空闲,可以接收任务 +- RUNNING:会话正在执行任务 +- BUSY:会话正忙 +- SHUTTING_DOWN:会话正在关闭 +- DEAD:会话已死亡 +- SUCCESS:会话成功完成 +- KILLED:会话被终止 + +LivyEngineExecutor通过轮询机制监控会话状态,直到任务完成或失败。 + +### 资源调度平台类型 + +DataVines支持多种资源调度平台,通过ResourceSchedulePlatformType枚举定义: + +```java +public enum ResourceSchedulePlatformType { + LOCAL(0,"local"), + YARN(1,"yarn"), + K8S(2,"k8s"); +} +``` + +用户可以根据部署环境选择合适的资源调度平台。不同的平台可能需要不同的配置参数和连接方式。 + +```mermaid +stateDiagram-v2 +[*] --> NOT_STARTED +NOT_STARTED --> STARTING +STARTING --> RECOVERING +STARTING --> IDLE +RECOVERING --> IDLE +IDLE --> RUNNING +RUNNING --> BUSY +BUSY --> IDLE +BUSY --> RUNNING +IDLE --> SHUTTING_DOWN +RUNNING --> SHUTTING_DOWN +BUSY --> SHUTTING_DOWN +SHUTTING_DOWN --> DEAD +IDLE --> DEAD +RUNNING --> DEAD +BUSY --> DEAD +IDLE --> KILLED +RUNNING --> KILLED +BUSY --> KILLED +IDLE --> SUCCESS +RUNNING --> SUCCESS +BUSY --> SUCCESS +DEAD --> [*] +KILLED --> [*] +SUCCESS --> [*] +``` + +**Diagram sources** +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java#L1-L47) +- [ResourceSchedulePlatformType.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\ResourceSchedulePlatformType.java#L1-L61) + +**Section sources** +- [LivyStates.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\LivyStates.java#L1-L47) +- [ResourceSchedulePlatformType.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\enums\ResourceSchedulePlatformType.java#L1-L61) + +## Spark参数配置 + +通过Livy提交Spark任务时,需要配置一系列Spark相关参数。这些参数通过SparkParameters和LivySparkParameters类进行定义和管理。 + +### 核心参数配置 + +#### SparkParameters类 +- `mainJar`:主JAR包路径 +- `mainClass`:主类名称 +- `deployMode`:部署模式(client/cluster) +- `driverCores`:Driver核心数 +- `driverMemory`:Driver内存 +- `numExecutors`:Executor数量 +- `executorCores`:每个Executor的核心数 +- `executorMemory`:每个Executor的内存 +- `appName`:应用名称 +- `queue`:YARN队列名称 +- `programType`:程序类型(JAVA/SCALA/PYTHON) +- `sparkVersion`:Spark版本 +- `jars`:依赖JAR包列表 + +#### LivySparkParameters类 +- `className`:主类名称 +- `file`:主文件路径 +- `args`:命令行参数 +- `jars`:依赖JAR包列表 +- `conf`:Spark配置 +- `name`:应用名称 +- `queue`:队列名称 +- `proxyUser`:代理用户 + +### 参数映射关系 + +LivyEngineExecutor在buildCommand()方法中将SparkParameters转换为LivySparkParameters,实现参数的映射和转换: + +```mermaid +flowchart TD +A[SparkParameters] --> B[参数验证] +B --> C[设置主类] +C --> D[设置资源参数] +D --> E[设置JAR包路径] +E --> F[设置配置参数] +F --> G[LivySparkParameters] +G --> H[JSON序列化] +H --> I[HTTP请求体] +``` + +**Section sources** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\SparkParameters.java#L1-L223) +- [LivySparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\parameter\LivySparkParameters.java#L1-L194) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L97-L236) + +## Livy状态监控 + +LivyEngineExecutor通过轮询机制监控任务执行状态,确保能够及时获取任务完成或失败的通知。 + +### 状态监控流程 + +1. 提交任务后获取会话ID +2. 定期调用Livy REST API查询会话状态 +3. 根据状态码判断任务执行情况 +4. 当任务完成(SUCCESS)或失败(DEAD/ERROR/KILLED)时停止轮询 +5. 返回执行结果 + +### 状态转换逻辑 + +```mermaid +flowchart TD +A[开始监控] --> B{获取状态} +B --> C[状态为SUCCESS] +C --> D[标记成功] +D --> E[结束] +B --> F[状态为DEAD/ERROR/KILLED] +F --> G[标记失败] +G --> E +B --> H[状态为RUNNING/BUSY] +H --> I[等待一段时间] +I --> B +B --> J[状态为IDLE] +J --> K[检查是否有任务] +K --> L[有任务则继续] +L --> B +K --> M[无任务则结束] +M --> E +``` + +LivyTaskSubmitHelper的processResultOfLivyState方法实现了状态监控的核心逻辑,使用Stopper.isRunning()作为循环条件,通过Thread.sleep()实现轮询间隔。 + +**Section sources** +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L38-L143) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) + +## 配置示例 + +以下是在DataVines中配置Livy提交Spark任务的完整示例: + +### application.yaml配置 + +```yaml +# Livy服务器配置 +livy: + uri: http://livy-server:8998/batches + need.kerberos: false + task: + jar: + lib: + path: hdfs:///datavines/lib + jars: datavines-engine-spark-1.0.0-SNAPSHOT.jar,datavines-connector-jdbc-1.0.0-SNAPSHOT.jar + proxyUser: livy + task: + appId: + retry: + count: 2 + +# 资源调度平台 +resource: + schedule: + platform: + type: yarn + +# YARN配置 +yarn: + uri: http://yarn-resourcemanager:8088/ +``` + +### 任务参数配置 + +```json +{ + "engineParameter": { + "mainJar": "/lib/datavines-core-1.0.0-SNAPSHOT.jar", + "mainClass": "io.datavines.engine.spark.core.SparkDataVinesBootstrap", + "deployMode": "cluster", + "driverCores": 2, + "driverMemory": "2g", + "numExecutors": 4, + "executorCores": 4, + "executorMemory": "8g", + "appName": "DataVines-Quality-Job", + "queue": "default", + "programType": "JAVA", + "sparkVersion": "SPARK3", + "jars": "--jars hdfs:///lib/dependency1.jar,hdfs:///lib/dependency2.jar" + }, + "applicationParameter": { + "jobConfig": { + "jobType": "DATA_QUALITY", + "source": { + "type": "JDBC", + "parameters": { + "jdbcUrl": "jdbc:mysql://localhost:3306/test", + "username": "user", + "password": "pass" + } + }, + "sink": { + "type": "JDBC", + "parameters": { + "jdbcUrl": "jdbc:mysql://localhost:3306/report", + "username": "user", + "password": "pass" + } + } + } + } +} +``` + +**Section sources** +- [application.yaml](file://datavines-server\src\main\resources\application.yaml#L1-L96) + +## 性能优化建议 + +为了确保通过Livy提交Spark任务的性能和稳定性,建议遵循以下优化策略: + +### 资源配置优化 +- 合理设置Executor数量和资源:根据数据量和计算复杂度调整numExecutors、executorCores和executorMemory参数 +- 优化Driver资源配置:确保Driver有足够的内存处理元数据和协调任务 +- 使用合适的队列:将任务提交到适当的YARN队列,避免资源争用 + +### 连接与通信优化 +- 调整轮询间隔:根据任务执行时间调整状态查询的轮询间隔,避免过于频繁的请求 +- 配置重试机制:设置适当的重试次数和间隔,应对网络波动 +- 使用连接池:对于频繁的任务提交,考虑使用HTTP连接池提高效率 + +### JAR包管理优化 +- 预上传依赖JAR包:将常用的依赖JAR包预先上传到HDFS,避免每次提交时重复上传 +- 使用本地缓存:在Livy服务器端配置JAR包缓存,减少网络传输 +- 优化JAR包大小:精简依赖,减少不必要的库文件 + +### 监控与日志优化 +- 启用详细日志:在调试阶段启用详细的日志记录,便于问题排查 +- 设置合理的日志级别:生产环境中使用适当的日志级别,避免日志文件过大 +- 集成监控系统:将Livy任务状态集成到统一的监控平台 + +## 故障排查指南 + +当通过Livy提交Spark任务遇到问题时,可以按照以下步骤进行排查: + +### 常见问题及解决方案 + +#### 连接问题 +- **症状**:无法连接到Livy服务器 +- **排查步骤**: + 1. 检查livy.uri配置是否正确 + 2. 验证网络连通性 + 3. 检查Livy服务器是否正常运行 + 4. 如果使用Kerberos,验证认证配置是否正确 + +#### 认证问题 +- **症状**:认证失败,返回401错误 +- **排查步骤**: + 1. 检查livy.need.kerberos配置 + 2. 验证principal和keytab文件路径 + 3. 确认Kerberos票据是否有效 + +#### 资源不足 +- **症状**:任务提交后长时间处于STARTING状态 +- **排查步骤**: + 1. 检查集群资源使用情况 + 2. 验证YARN队列配置 + 3. 调整资源请求参数 + +#### 任务失败 +- **症状**:任务状态变为DEAD或ERROR +- **排查步骤**: + 1. 查看Livy服务器日志 + 2. 检查Spark应用日志 + 3. 验证JAR包路径和依赖 + +### 日志分析 +- 查看DataVines系统的执行日志 +- 检查Livy服务器的REST API访问日志 +- 分析Spark应用的执行日志 +- 关注关键错误信息和堆栈跟踪 + +### 监控指标 +- 监控Livy会话创建成功率 +- 跟踪任务执行时间分布 +- 记录资源使用情况 +- 设置异常告警 + +**Section sources** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L38-L143) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256.md" new file mode 100644 index 00000000..398795d1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256.md" @@ -0,0 +1,418 @@ +# Spark执行配置 + + +**本文档引用的文件** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [LivySparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/parameter/LivySparkParameters.java) +- [SparkConstants.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkConstants.java) +- [BaseSparkConfigurationBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/BaseSparkConfigurationBuilder.java) +- [SparkVersion.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkVersion.java) +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [配置构建器工作原理](#配置构建器工作原理) +4. [Spark参数设置](#spark参数设置) +5. [执行模式配置](#执行模式配置) +6. [Spark与Livy执行器配置差异](#spark与livy执行器配置差异) +7. [性能优化建议](#性能优化建议) +8. [故障排查指南](#故障排查指南) + +## 简介 +DataVines通过Spark执行引擎提供数据质量检测功能,支持直接提交和Livy两种执行模式。本文档详细说明Spark执行配置方法,包括配置构建器工作原理、Spark参数设置、执行模式配置以及性能优化和故障排查。 + +**本文档引用的文件** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) + +## 核心组件 + +DataVines的Spark执行配置涉及多个核心组件,包括SparkEngineExecutor、LivyEngineExecutor、SparkParameters等。这些组件协同工作,实现Spark任务的配置、提交和执行。 + +```mermaid +classDiagram +class SparkEngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++after() ++getProcessResult() ++getTaskRequest() ++buildCommand() +} +class LivyEngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++after() ++getProcessResult() ++getTaskRequest() ++buildCommand() +} +class SparkParameters { ++mainJar : String ++mainClass : String ++deployMode : String ++mainArgs : String ++driverCores : int ++driverMemory : String ++numExecutors : int ++executorCores : int ++executorMemory : String ++appName : String ++queue : String ++others : String ++programType : ProgramType ++sparkVersion : String ++jars : String +} +class LivySparkParameters { ++className : String ++executorCores : Integer ++driverMemory : String ++numExecutors : Integer ++driverCores : Integer ++executorMemory : String ++name : String ++queue : String ++proxyUser : String ++file : String ++args : String[] ++jars : String[] ++conf : Map~String, Object~ +} +SparkEngineExecutor --> SparkParameters : "使用" +LivyEngineExecutor --> SparkParameters : "解析" +LivyEngineExecutor --> LivySparkParameters : "构建" +SparkParameters --> ProgramType : "引用" +``` + +**图源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [LivySparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/parameter/LivySparkParameters.java) + +**本文档引用的文件** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [LivySparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/parameter/LivySparkParameters.java) + +## 配置构建器工作原理 + +BaseSparkConfigurationBuilder是Spark配置构建的核心类,负责构建Spark任务所需的环境配置、数据源配置和目标配置。它通过继承JobConfigurationBuilder接口,实现了配置的初始化和构建过程。 + +```mermaid +sequenceDiagram +participant Builder as BaseSparkConfigurationBuilder +participant Job as JobExecutionInfo +participant Param as JobExecutionParameter +participant Config as DataVinesJobConfig +Builder->>Builder : init(inputParameter, jobExecutionInfo) +Builder->>Builder : buildName() +Builder->>Builder : buildEnvConfig() +Builder->>Builder : buildSourceConfigs() +Builder->>Builder : buildTransformConfigs() +Builder->>Builder : buildSinkConfigs() +Builder-->>Config : build() +Note over Builder,Config : 构建完整的DataVinesJobConfig +``` + +**图源** +- [BaseSparkConfigurationBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/BaseSparkConfigurationBuilder.java) + +**本文档引用的文件** +- [BaseSparkConfigurationBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/BaseSparkConfigurationBuilder.java) + +## Spark参数设置 + +Spark参数设置是通过SparkParameters类实现的,该类包含了Spark任务执行所需的所有参数。参数设置分为基本参数、资源参数、队列参数和高级参数。 + +### 基本参数 +| 参数 | 描述 | 示例 | +|------|------|------| +| **mainJar** | 主JAR包路径 | /path/to/data-quality.jar | +| **mainClass** | 主类名 | io.datavines.engine.spark.core.SparkDataVinesBootstrap | +| **deployMode** | 部署模式 | cluster/client | +| **programType** | 程序类型 | JAVA/SCALA/PYTHON | +| **sparkVersion** | Spark版本 | SPARK2/SPARK3 | + +### 资源参数 +| 参数 | 描述 | 示例 | +|------|------|------| +| **driverCores** | Driver核心数 | 2 | +| **driverMemory** | Driver内存 | 2g | +| **numExecutors** | Executor数量 | 4 | +| **executorCores** | 每个Executor核心数 | 2 | +| **executorMemory** | 每个Executor内存 | 4g | + +### 队列参数 +| 参数 | 描述 | 示例 | +|------|------|------| +| **appName** | 应用名称 | data-quality-job | +| **queue** | YARN队列 | default | +| **jars** | 附加JAR包 | --jars /path/to/lib1.jar,/path/to/lib2.jar | + +### 高级参数 +| 参数 | 描述 | 示例 | +|------|------|------| +| **others** | 其他参数 | --conf spark.sql.adaptive.enabled=true | +| **mainArgs** | 主程序参数 | JSON格式的配置参数 | + +```mermaid +classDiagram +class SparkConstants { ++MAIN_CLASS : String ++SPARK_NAME : String ++SPARK_QUEUE : String ++DEPLOY_MODE : String ++DRIVER_CORES : String ++DRIVER_MEMORY : String ++MASTER : String ++NUM_EXECUTORS : String ++EXECUTOR_CORES : String ++EXECUTOR_MEMORY : String +} +class ProgramType { ++JAVA ++SCALA ++PYTHON +} +class SparkVersion { ++SPARK2 ++SPARK3 +} +SparkParameters --> SparkConstants : "引用" +SparkParameters --> ProgramType : "引用" +SparkParameters --> SparkVersion : "引用" +``` + +**图源** +- [SparkConstants.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkConstants.java) +- [ProgramType.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/ProgramType.java) +- [SparkVersion.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkVersion.java) + +**本文档引用的文件** +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [SparkConstants.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkConstants.java) +- [ProgramType.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/ProgramType.java) +- [SparkVersion.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkVersion.java) + +## 执行模式配置 + +DataVines支持两种Spark执行模式:直接提交模式和Livy模式。两种模式的配置方式有所不同,但都基于相同的参数体系。 + +### 直接提交模式 +直接提交模式通过SparkEngineExecutor实现,使用spark-submit命令直接提交任务到YARN集群。 + +```mermaid +flowchart TD +Start([开始]) --> BuildConfig["构建Spark配置"] +BuildConfig --> CreateArgs["创建Spark参数"] +CreateArgs --> BuildCommand["构建spark-submit命令"] +BuildCommand --> Execute["执行命令"] +Execute --> Monitor["监控任务状态"] +Monitor --> End([结束]) +subgraph "命令构建" +BuildCommand --> SPARK2_COMMAND["SPARK2_COMMAND"] +BuildCommand --> ARGS["SparkArgsUtils.buildArgs()"] +BuildCommand --> JOIN["String.join(\" \", args)"] +end +``` + +**图源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java) + +### Livy模式 +Livy模式通过LivyEngineExecutor实现,使用REST API将任务提交到Livy服务器。 + +```mermaid +flowchart TD +Start([开始]) --> ParseParam["解析SparkParameters"] +ParseParam --> CreateLivyParam["创建LivySparkParameters"] +CreateLivyParam --> SetFile["设置JAR文件路径"] +SetFile --> SetJars["设置附加JAR包"] +SetJars --> SetArgs["设置任务参数"] +SetArgs --> SetConf["设置配置参数"] +SetConf --> BuildJSON["构建JSON请求"] +BuildJSON --> PostLivy["POST到Livy API"] +PostLivy --> Monitor["监控任务状态"] +Monitor --> End([结束]) +``` + +**图源** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) + +**本文档引用的文件** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java) + +## Spark与Livy执行器配置差异 + +SparkEngineExecutor和LivyEngineExecutor在配置上有显著差异,主要体现在参数格式、JAR包管理和提交方式上。 + +### 参数格式差异 +| 特性 | SparkEngineExecutor | LivyEngineExecutor | +|------|-------------------|-------------------| +| **参数格式** | 命令行参数列表 | JSON格式 | +| **主类设置** | --class参数 | className字段 | +| **JAR包设置** | --jars参数 | jars列表 | +| **配置设置** | --conf参数 | conf映射 | +| **参数传递** | mainArgs字符串 | args列表 | + +### JAR包管理差异 +SparkEngineExecutor从本地文件系统加载JAR包,而LivyEngineExecutor从HDFS加载JAR包。 + +```mermaid +classDiagram +class SparkEngineExecutor { ++buildCommand() ++basePath : String ++pluginDir : String ++FileUtils.getFileList() +} +class LivyEngineExecutor { ++buildCommand() ++jarLibPath : String ++taskJars : String ++splitToList() +} +SparkEngineExecutor --> "本地文件系统" : "读取" +LivyEngineExecutor --> "HDFS" : "读取" +note right of SparkEngineExecutor +从本地libs目录和plugins目录 +加载JAR包 +end note +note right of LivyEngineExecutor +从HDFS指定路径加载 +JAR包 +end note +``` + +**图源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) + +### 提交方式差异 +| 特性 | SparkEngineExecutor | LivyEngineExecutor | +|------|-------------------|-------------------| +| **提交方式** | shell命令执行 | REST API调用 | +| **执行过程** | ShellCommandProcess | LivyCommandProcess | +| **状态监控** | 进程状态 | Livy REST API | +| **错误处理** | 异常捕获 | HTTP状态码 | +| **超时处理** | 超时机制 | 重试机制 | + +**本文档引用的文件** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) + +## 性能优化建议 + +### 资源分配优化 +合理的资源分配是性能优化的关键。根据工作负载特征调整资源参数: + +```mermaid +flowchart TD +WorkloadType([工作负载类型]) --> SmallData["小数据量"] +WorkloadType --> MediumData["中等数据量"] +WorkloadType --> LargeData["大数据量"] +SmallData --> SmallConfig["driverCores=1
driverMemory=1g
numExecutors=2
executorCores=1
executorMemory=2g"] +MediumData --> MediumConfig["driverCores=2
driverMemory=2g
numExecutors=4
executorCores=2
executorMemory=4g"] +LargeData --> LargeConfig["driverCores=4
driverMemory=4g
numExecutors=8
executorCores=4
executorMemory=8g"] +PerformanceGoal([性能目标]) --> Speed["速度优先"] +PerformanceGoal --> Cost["成本优先"] +PerformanceGoal --> Balance["平衡"] +Speed --> HighResource["高资源配置"] +Cost --> LowResource["低资源配置"] +Balance --> MediumResource["中等资源配置"] +``` + +### 配置优化策略 +1. **Executor优化**:确保Executor内存和核心数的合理比例,通常内存:核心数为4:1到8:1 +2. **并行度优化**:设置合理的num-executors和executor-cores,充分利用集群资源 +3. **内存优化**:合理分配Driver和Executor内存,避免OOM +4. **队列优化**:选择合适的YARN队列,避免资源争用 + +### Spark特定优化 +```mermaid +classDiagram +class SparkRuntimeEnvironment { ++createSparkConf() ++createStreamingContext() ++sparkSession() ++streamingContext() ++enableSparkHiveSupport() ++getExecution() +} +class SparkConf { ++set(key, value) ++set("spark.sql.crossJoin.enabled", "true") +} +SparkRuntimeEnvironment --> SparkConf : "创建" +note right of SparkRuntimeEnvironment +启用跨连接支持 +配置流式处理上下文 +支持Spark Hive +end note +``` + +**图源** +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) + +**本文档引用的文件** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) + +## 故障排查指南 + +### 常见问题及解决方案 +| 问题现象 | 可能原因 | 解决方案 | +|---------|--------|---------| +| **任务提交失败** | 参数配置错误 | 检查SparkParameters必填字段 | +| **资源不足** | 资源配置过高 | 降低executor-memory或num-executors | +| **连接超时** | 网络问题或Livy服务不可用 | 检查网络连接和Livy服务状态 | +| **JAR包找不到** | JAR路径配置错误 | 检查mainJar路径和HDFS路径 | +| **权限不足** | 用户权限不足 | 检查用户权限和proxyUser配置 | + +### 日志分析 +通过日志分析可以快速定位问题: + +```mermaid +flowchart TD +LogAnalysis([日志分析]) --> FindError["查找错误信息"] +FindError --> ClassifyError["分类错误类型"] +ClassifyError --> ConfigurationError["配置错误"] +ClassifyError --> ResourceError["资源错误"] +ClassifyError --> NetworkError["网络错误"] +ClassifyError --> PermissionError["权限错误"] +ConfigurationError --> CheckParams["检查参数配置"] +ResourceError --> CheckResources["检查资源分配"] +NetworkError --> CheckConnectivity["检查网络连接"] +PermissionError --> CheckAuth["检查认证信息"] +CheckParams --> FixConfig["修正配置"] +CheckResources --> AdjustResources["调整资源"] +CheckConnectivity --> FixNetwork["修复网络"] +CheckAuth --> UpdateAuth["更新认证"] +``` + +### 参数验证 +在提交任务前,应验证关键参数: + +```java +// SparkParameters.checkParameters() +public boolean checkParameters() { + return mainJar != null && programType != null; +} +``` + +确保mainJar和programType等必填参数已正确设置。 + +**本文档引用的文件** +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256/Spark\347\233\264\346\216\245\346\211\247\350\241\214\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256/Spark\347\233\264\346\216\245\346\211\247\350\241\214\351\205\215\347\275\256.md" new file mode 100644 index 00000000..6f43603d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/Spark\346\211\247\350\241\214\351\205\215\347\275\256/Spark\347\233\264\346\216\245\346\211\247\350\241\214\351\205\215\347\275\256.md" @@ -0,0 +1,412 @@ +# Spark直接执行配置 + + +**本文档引用文件** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java) +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [SparkConstants.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkConstants.java) +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\SparkRuntimeEnvironment.java) +- [SparkDataVinesBootstrap.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-core\src\main\java\io\datavines\engine\spark\core\SparkDataVinesBootstrap.java) +- [SparkDataProfileMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkDataProfileMetricBuilder.java) +- [SparkSingleTableMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSingleTableMetricBuilder.java) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java) +- [ProgramType.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\ProgramType.java) +- [SparkSinkSqlBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSinkSqlBuilder.java) +- [CommonConstants.java](file://datavines-common\src\main\java\io\datavines\common\CommonConstants.java) +- [SparkEngineParameter.java](file://datavines-common\src\main\java\io\datavines\common\entity\SparkEngineParameter.java) + + +## 目录 +1. [简介](#简介) +2. [核心组件](#核心组件) +3. [配置构建流程](#配置构建流程) +4. [Spark参数设置](#spark参数设置) +5. [资源分配策略](#资源分配策略) +6. [队列配置](#队列配置) +7. [执行环境初始化](#执行环境初始化) +8. [配置示例](#配置示例) +9. [性能调优建议](#性能调优建议) +10. [常见问题解决方案](#常见问题解决方案) + +## 简介 +DataVines通过SparkEngineExecutor直接提交Spark任务,实现数据质量检查和数据剖析等功能。本配置文档详细说明了如何通过BaseSparkConfigurationBuilder构建配置,设置Spark参数,分配资源,配置队列以及初始化执行环境。文档涵盖了从配置构建到任务执行的完整流程,并提供配置示例、性能调优建议和常见问题解决方案,确保用户能够正确配置和优化Spark直接执行模式。 + +## 核心组件 + +DataVines中Spark直接执行的核心组件包括SparkEngineExecutor、BaseSparkConfigurationBuilder、SparkParameters和SparkRuntimeEnvironment。SparkEngineExecutor负责构建和执行Spark命令,BaseSparkConfigurationBuilder负责构建任务配置,SparkParameters定义了Spark任务的参数,而SparkRuntimeEnvironment则负责初始化Spark执行环境。 + +```mermaid +classDiagram +class SparkEngineExecutor { ++init(JobExecutionRequest, Logger, Configurations) ++execute() ++after() ++getProcessResult() ++getTaskRequest() +-buildCommand() +} +class BaseSparkConfigurationBuilder { ++getEnvConfig() ++getSourceConfigs() ++buildSinkConfigs() ++buildTransformConfigs() ++getValidateResultDataSinkConfig(ExpectedValue, String, String, Map) ++getOutputTable(String, String, String) ++getTableAlias(String, String, String, String) +} +class SparkParameters { ++mainJar : String ++mainClass : String ++deployMode : String ++mainArgs : String ++driverCores : int ++driverMemory : String ++numExecutors : int ++executorCores : int ++executorMemory : String ++appName : String ++queue : String ++others : String ++programType : ProgramType ++sparkVersion : String ++jars : String +} +class SparkRuntimeEnvironment { ++sparkSession : SparkSession ++streamingContext : StreamingContext ++config : Config ++enableSparkHiveSupport : boolean ++setConfig(Config) ++getConfig() ++checkConfig() ++prepare() ++createSparkConf() ++createStreamingContext() ++sparkSession() ++streamingContext() ++enableSparkHiveSupport() ++getExecution() +} +SparkEngineExecutor --> BaseSparkConfigurationBuilder : "使用" +SparkEngineExecutor --> SparkParameters : "使用" +SparkEngineExecutor --> SparkRuntimeEnvironment : "使用" +BaseSparkConfigurationBuilder --> SparkSinkSqlBuilder : "使用" +SparkRuntimeEnvironment --> SparkBatchExecution : "创建" +``` + +**图表来源** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java) +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\SparkRuntimeEnvironment.java) +- [SparkSinkSqlBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSinkSqlBuilder.java) + +**章节来源** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java) +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\SparkRuntimeEnvironment.java) + +## 配置构建流程 + +DataVines中的Spark任务配置构建流程由BaseSparkConfigurationBuilder及其子类负责。配置构建器根据任务类型(如数据剖析、单表质量检查、多表值比较等)构建相应的配置。配置构建流程包括环境配置、数据源配置、转换配置和接收器配置的构建。 + +```mermaid +flowchart TD +Start([开始]) --> GetEnvConfig["构建环境配置"] +GetEnvConfig --> GetSourceConfigs["构建数据源配置"] +GetSourceConfigs --> BuildTransformConfigs["构建转换配置"] +BuildTransformConfigs --> BuildSinkConfigs["构建接收器配置"] +BuildSinkConfigs --> End([结束]) +subgraph "环境配置" +GetEnvConfig --> EnableHiveSupport{"启用Spark Hive支持?"} +EnableHiveSupport --> |是| SetHiveSupport["设置enableSparkHiveSupport=true"] +EnableHiveSupport --> |否| Continue1 +end +subgraph "数据源配置" +GetSourceConfigs --> ExtractTables["从SQL中提取表名"] +ExtractTables --> ValidateTables{"表名存在?"} +ValidateTables --> |否| ThrowException["抛出DataVinesException"] +ValidateTables --> |是| ProcessTables["处理表名和别名"] +ProcessTables --> AddSourceConfig["添加数据源配置"] +end +subgraph "接收器配置" +BuildSinkConfigs --> GetMetricType["获取指标类型"] +GetMetricType --> IsCustomSql{"自定义SQL?"} +IsCustomSql --> |是| UseCustomSql["使用自定义SQL构建接收器"] +IsCustomSql --> |否| UseDefaultSql["使用默认SQL构建接收器"] +UseCustomSql --> SetSaveMode["设置保存模式为UPSERT"] +UseDefaultSql --> SetSaveMode +end +``` + +**图表来源** +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java) +- [SparkDataProfileMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkDataProfileMetricBuilder.java) +- [SparkSingleTableMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSingleTableMetricBuilder.java) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java) + +**章节来源** +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java) +- [SparkDataProfileMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkDataProfileMetricBuilder.java) +- [SparkSingleTableMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkSingleTableMetricBuilder.java) +- [SparkMultiTableValueComparisonMetricBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\SparkMultiTableValueComparisonMetricBuilder.java) + +## Spark参数设置 + +Spark参数设置通过SparkParameters类进行,该类定义了Spark任务的所有参数。参数设置包括程序类型、Spark版本、主类、JAR包路径、部署模式、驱动程序和执行器的资源配置等。 + +```mermaid +classDiagram +class SparkParameters { ++mainJar : String ++mainClass : String ++deployMode : String ++mainArgs : String ++driverCores : int ++driverMemory : String ++numExecutors : int ++executorCores : int ++executorMemory : String ++appName : String ++queue : String ++others : String ++programType : ProgramType ++sparkVersion : String ++jars : String +} +class ProgramType { ++JAVA ++SCALA ++PYTHON +} +SparkParameters --> ProgramType : "包含" +``` + +**图表来源** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [ProgramType.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\ProgramType.java) + +**章节来源** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [ProgramType.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\ProgramType.java) + +## 资源分配策略 + +DataVines中的资源分配策略通过Spark参数进行配置,包括驱动程序和执行器的CPU核心数和内存大小。资源分配策略直接影响任务的性能和稳定性。 + +```mermaid +flowchart TD +Start([开始]) --> SetDriverCores["设置驱动程序核心数"] +SetDriverCores --> SetDriverMemory["设置驱动程序内存"] +SetDriverMemory --> SetNumExecutors["设置执行器数量"] +SetNumExecutors --> SetExecutorCores["设置执行器核心数"] +SetExecutorCores --> SetExecutorMemory["设置执行器内存"] +SetExecutorMemory --> End([结束]) +subgraph "驱动程序资源配置" +SetDriverCores --> ValidateDriverCores{"核心数>0?"} +ValidateDriverCores --> |是| AddDriverCores["添加--driver-cores参数"] +ValidateDriverCores --> |否| SkipDriverCores["跳过"] +SetDriverMemory --> ValidateDriverMemory{"内存非空?"} +ValidateDriverMemory --> |是| AddDriverMemory["添加--driver-memory参数"] +ValidateDriverMemory --> |否| SkipDriverMemory["跳过"] +end +subgraph "执行器资源配置" +SetNumExecutors --> ValidateNumExecutors{"数量>0?"} +ValidateNumExecutors --> |是| AddNumExecutors["添加--num-executors参数"] +ValidateNumExecutors --> |否| SkipNumExecutors["跳过"] +SetExecutorCores --> ValidateExecutorCores{"核心数>0?"} +ValidateExecutorCores --> |是| AddExecutorCores["添加--executor-cores参数"] +ValidateExecutorCores --> |否| SkipExecutorCores["跳过"] +SetExecutorMemory --> ValidateExecutorMemory{"内存非空?"} +ValidateExecutorMemory --> |是| AddExecutorMemory["添加--executor-memory参数"] +ValidateExecutorMemory --> |否| SkipExecutorMemory["跳过"] +end +``` + +**图表来源** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java) +- [SparkConstants.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkConstants.java) + +**章节来源** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java) +- [SparkConstants.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkConstants.java) + +## 队列配置 + +队列配置用于指定Spark任务提交到YARN的哪个队列。队列配置有助于资源管理和任务调度。 + +```mermaid +sequenceDiagram +participant UI as "用户界面" +participant Executor as "SparkEngineExecutor" +participant ArgsUtils as "SparkArgsUtils" +participant Params as "SparkParameters" +UI->>Executor : 提交任务配置 +Executor->>Executor : 解析SparkParameters +Executor->>ArgsUtils : 调用buildArgs() +ArgsUtils->>Params : 获取队列名称 +Params-->>ArgsUtils : queue +ArgsUtils->>ArgsUtils : 检查部署模式和队列参数 +ArgsUtils->>ArgsUtils : 添加--queue参数 +ArgsUtils-->>Executor : 返回参数列表 +Executor->>Executor : 构建完整命令 +Executor-->>UI : 返回执行结果 +``` + +**图表来源** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java) +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) + +**章节来源** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java) +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) + +## 执行环境初始化 + +执行环境初始化由SparkRuntimeEnvironment负责,包括SparkSession的创建、Hive支持的启用、流式处理上下文的创建等。 + +```mermaid +flowchart TD +Start([开始]) --> SetConfig["设置配置"] +SetConfig --> CheckHiveSupport["检查是否启用Hive支持"] +CheckHiveSupport --> |是| EnableHive["启用Hive支持"] +CheckHiveSupport --> |否| SkipHive["跳过"] +EnableHive --> CreateSparkSession["创建SparkSession"] +SkipHive --> CreateSparkSession +CreateSparkSession --> CreateStreamingContext["创建流式处理上下文"] +CreateStreamingContext --> SetExecution["设置执行器"] +SetExecution --> End([结束]) +subgraph "SparkSession创建" +CreateSparkSession --> CreateConf["创建SparkConf"] +CreateConf --> SetCrossJoin["设置spark.sql.crossJoin.enabled=true"] +SetCrossJoin --> BuildSession["构建SparkSession"] +BuildSession --> GetOrCreate["getOrCreate()"] +end +subgraph "流式处理上下文创建" +CreateStreamingContext --> GetDuration["从配置获取批处理持续时间"] +GetDuration --> CreateContext["创建StreamingContext"] +CreateContext --> SetContext["设置streamingContext"] +end +``` + +**图表来源** +- [SparkRuntimeEnvironment.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\SparkRuntimeEnvironment.java) +- [SparkBatchExecution.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\batch\SparkBatchExecution.java) + +**章节来源** +- [SparkRuntimeEnvironment.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\SparkRuntimeEnvironment.java) +- [SparkBatchExecution.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-api\src\main\java\io\datavines\engine\spark\api\batch\SparkBatchExecution.java) + +## 配置示例 + +以下是一个完整的Spark任务配置示例,展示了如何设置各种参数: + +```json +{ + "programType": "JAVA", + "deployMode": "cluster", + "driverCores": 2, + "driverMemory": "4g", + "numExecutors": 5, + "executorCores": 4, + "executorMemory": "8g", + "appName": "DataVines-Quality-Check", + "queue": "default", + "others": "--conf spark.serializer=org.apache.spark.serializer.KryoSerializer --conf spark.sql.adaptive.enabled=true", + "sparkVersion": "2.4", + "jars": "--jars hdfs://path/to/dependency1.jar,hdfs://path/to/dependency2.jar" +} +``` + +**章节来源** +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [SparkEngineParameter.java](file://datavines-common\src\main\java\io\datavines\common\entity\SparkEngineParameter.java) + +## 性能调优建议 + +为了优化Spark任务的性能,建议采取以下措施: + +1. **合理分配资源**:根据数据量和计算复杂度合理设置执行器数量、核心数和内存大小。 +2. **启用自适应查询执行**:通过`spark.sql.adaptive.enabled=true`启用自适应查询执行,优化查询计划。 +3. **使用Kryo序列化**:通过`spark.serializer=org.apache.spark.serializer.KryoSerializer`使用Kryo序列化,提高序列化性能。 +4. **调整并行度**:根据集群资源和数据量调整`spark.sql.shuffle.partitions`参数。 +5. **启用动态资源分配**:通过`spark.dynamicAllocation.enabled=true`启用动态资源分配,提高资源利用率。 + +```mermaid +flowchart TD +Start([开始]) --> AssessDataSize["评估数据量和计算复杂度"] +AssessDataSize --> AllocateResources["合理分配资源"] +AllocateResources --> EnableAQE["启用自适应查询执行"] +EnableAQE --> UseKryo["使用Kryo序列化"] +UseKryo --> AdjustParallelism["调整并行度"] +AdjustParallelism --> EnableDynamicAllocation["启用动态资源分配"] +EnableDynamicAllocation --> MonitorPerformance["监控性能"] +MonitorPerformance --> Optimize["持续优化"] +Optimize --> End([结束]) +``` + +**图表来源** +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java) +- [SparkConstants.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkConstants.java) + +**章节来源** +- [SparkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkArgsUtils.java) +- [SparkConstants.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkConstants.java) + +## 常见问题解决方案 + +### 问题1:任务提交失败,提示"Application application_XXXXXX failed 2 times due to AM Container for X failed" +**解决方案**:检查驱动程序内存是否足够,增加`driverMemory`参数的值。 + +### 问题2:执行器频繁失败 +**解决方案**:检查执行器内存是否足够,增加`executorMemory`参数的值,或减少`executorCores`以降低内存压力。 + +### 问题3:任务执行缓慢 +**解决方案**:增加执行器数量(`numExecutors`)和核心数(`executorCores`),或优化SQL查询。 + +### 问题4:无法连接到Hive metastore +**解决方案**:确保`enableSparkHiveSupport`设置为`true`,并检查Hive配置是否正确。 + +### 问题5:自定义JAR包未生效 +**解决方案**:确保`jars`参数正确指定了JAR包路径,并使用`--jars`前缀。 + +```mermaid +flowchart TD +Start([问题]) --> IdentifyIssue["识别问题类型"] +IdentifyIssue --> CheckResources["检查资源分配"] +CheckResources --> AdjustMemory["调整内存设置"] +AdjustMemory --> CheckConfiguration["检查配置"] +CheckConfiguration --> VerifyJars["验证JAR包"] +VerifyJars --> TestConnection["测试连接"] +TestConnection --> ResolveIssue["解决问题"] +ResolveIssue --> End([解决]) +subgraph "资源问题" +CheckResources --> InsufficientDriverMemory{"驱动程序内存不足?"} +InsufficientDriverMemory --> |是| IncreaseDriverMemory["增加driverMemory"] +CheckResources --> InsufficientExecutorMemory{"执行器内存不足?"} +InsufficientExecutorMemory --> |是| IncreaseExecutorMemory["增加executorMemory"] +end +subgraph "配置问题" +CheckConfiguration --> HiveSupportEnabled{"Hive支持启用?"} +HiveSupportEnabled --> |否| EnableHiveSupport["设置enableSparkHiveSupport=true"] +VerifyJars --> JarsCorrect{"JAR包路径正确?"} +JarsCorrect --> |否| FixJarsPath["修正JAR包路径"] +end +``` + +**图表来源** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java) + +**章节来源** +- [SparkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\SparkEngineExecutor.java) +- [SparkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-executor\src\main\java\io\datavines\engine\spark\executor\parameter\SparkParameters.java) +- [BaseSparkConfigurationBuilder.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-spark\datavines-engine-spark-config\src\main\java\io\datavines\engine\spark\config\BaseSparkConfigurationBuilder.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256.md" new file mode 100644 index 00000000..8dec1ee6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256.md" @@ -0,0 +1,314 @@ +# 执行引擎配置 + + +**本文档引用的文件** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java) +- [LivyStates.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java) +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) + + +## 目录 +1. [简介](#简介) +2. [执行引擎类型](#执行引擎类型) +3. [本地执行引擎配置](#本地执行引擎配置) +4. [Spark执行引擎配置](#spark执行引擎配置) +5. [Flink执行引擎配置](#flink执行引擎配置) +6. [资源调度平台配置](#资源调度平台配置) +7. [Livy集成配置](#livy集成配置) +8. [执行参数与资源分配](#执行参数与资源分配) +9. [执行模式与超时设置](#执行模式与超时设置) +10. [JVM参数与内存配置](#jvm参数与内存配置) +11. [执行状态监控](#执行状态监控) + +## 简介 +DataVines支持多种执行引擎,包括本地执行、Spark和Flink等分布式计算框架。本文档详细说明了各种执行引擎的配置方法,涵盖连接参数、资源分配、执行模式、超时设置等方面。同时,文档还解释了如何配置Livy、Yarn等资源调度平台,提供不同执行引擎的性能对比和适用场景建议,并说明如何配置执行环境的JVM参数、内存分配和GC策略,以及如何监控执行引擎的运行状态。 + +## 执行引擎类型 +DataVines支持以下几种执行引擎类型: +- **Local**:本地执行模式,适用于小规模数据处理和开发测试 +- **Spark**:基于Apache Spark的分布式计算引擎,适用于大规模批处理任务 +- **Flink**:基于Apache Flink的流处理引擎,适用于实时数据处理和流式计算 + +这些执行引擎通过统一的接口进行管理,用户可以根据具体需求选择合适的执行引擎。 + +**Section sources** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java) + +## 本地执行引擎配置 +本地执行引擎是最简单的执行模式,直接在当前JVM进程中执行任务。本地执行引擎不需要额外的集群资源,适合开发和测试环境。 + +本地执行引擎的核心是`LocalRuntimeEnvironment`类,它实现了`RuntimeEnvironment`接口,负责准备执行环境和获取执行器。本地执行环境主要管理数据库连接和SQL执行状态。 + +```mermaid +classDiagram +class LocalRuntimeEnvironment { ++Logger log ++ConnectionHolder sourceConnection ++ConnectionHolder targetConnection ++ConnectionHolder metadataConnection ++Statement currentStatement ++boolean stop ++prepare() ++getExecution() ++setConfig(Config config) ++getConfig() ++checkConfig() ++close() +} +class LocalExecution { ++execute(List sources, List transforms, List sinks) ++stop() ++prepare() +} +class ConnectionHolder { ++Connection connection ++close() +} +LocalRuntimeEnvironment --> LocalExecution : "创建" +LocalRuntimeEnvironment --> ConnectionHolder : "持有" +``` + +**Diagram sources** +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) + +**Section sources** +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) + +## Spark执行引擎配置 +Spark执行引擎基于Apache Spark框架,支持大规模数据处理。Spark执行环境通过`SparkRuntimeEnvironment`类实现,该类负责创建和管理SparkSession和StreamingContext。 + +Spark执行环境支持批处理和流处理两种模式,可以通过配置参数进行切换。执行环境还支持Hive集成,可以访问Hive元数据和表。 + +```mermaid +classDiagram +class SparkRuntimeEnvironment { ++SparkSession sparkSession ++StreamingContext streamingContext ++Config config ++boolean enableSparkHiveSupport ++prepare() ++getExecution() ++setConfig(Config config) ++getConfig() ++checkConfig() ++sparkSession() ++streamingContext() ++enableSparkHiveSupport() +} +class SparkBatchExecution { ++execute(List sources, List transforms, List sinks) ++stop() ++prepare() +} +class SparkStreamExecution { ++execute(List sources, List transforms, List sinks) ++stop() ++prepare() +} +SparkRuntimeEnvironment --> SparkSession : "创建" +SparkRuntimeEnvironment --> StreamingContext : "创建" +SparkRuntimeEnvironment --> SparkBatchExecution : "创建" +SparkRuntimeEnvironment --> SparkStreamExecution : "创建" +SparkRuntimeEnvironment ..> HiveSqlDialect : "注册" +``` + +**Diagram sources** +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) + +**Section sources** +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) + +## Flink执行引擎配置 +Flink执行引擎基于Apache Flink框架,专注于流式数据处理。Flink执行环境通过`FlinkRuntimeEnvironment`类实现,该类负责创建和管理StreamExecutionEnvironment和StreamTableEnvironment。 + +Flink执行环境支持批处理和流处理两种运行模式,可以通过配置参数进行切换。执行环境还提供了对Flink SQL的支持,可以执行复杂的流式SQL查询。 + +```mermaid +classDiagram +class FlinkRuntimeEnvironment { ++StreamExecutionEnvironment env ++StreamTableEnvironment tableEnv ++Config config ++prepare() ++getExecution() ++setConfig(Config config) ++getConfig() ++checkConfig() ++stop() +} +class FlinkStreamExecution { ++execute(List sources, List transforms, List sinks) ++stop() ++prepare() +} +FlinkRuntimeEnvironment --> StreamExecutionEnvironment : "获取" +FlinkRuntimeEnvironment --> StreamTableEnvironment : "创建" +FlinkRuntimeEnvironment --> FlinkStreamExecution : "创建" +``` + +**Diagram sources** +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) + +**Section sources** +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) + +## 资源调度平台配置 +DataVines支持多种资源调度平台,包括本地、Yarn和K8S。资源调度平台类型通过`ResourceSchedulePlatformType`枚举定义。 + +不同的资源调度平台有不同的执行器实现: +- **LOCAL**:使用本地执行器,直接在当前进程中执行任务 +- **YARN**:使用Yarn执行器,通过Yarn集群管理资源 +- **K8S**:使用K8S执行器,通过Kubernetes集群管理资源 + +Yarn执行器继承自`AbstractYarnEngineExecutor`,该类提供了Yarn应用的管理和终止功能。执行器通过YarnUtils工具类获取应用ID,并使用sudo命令终止Yarn应用。 + +```mermaid +classDiagram +class AbstractEngineExecutor { ++JobExecutionRequest jobExecutionRequest ++Logger logger ++boolean cancel ++ProcessResult processResult ++logHandle(List logs) ++isCancel() ++buildCommand() +} +class AbstractYarnEngineExecutor { ++ShellCommandProcess shellCommandProcess ++cancel() ++killYarnApplication() +} +class AbstractLivyEngineExecutor { ++LivyCommandProcess livyCommandProcess ++cancel() +} +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +AbstractEngineExecutor <|-- AbstractLivyEngineExecutor +AbstractYarnEngineExecutor --> ShellCommandProcess : "持有" +AbstractLivyEngineExecutor --> LivyCommandProcess : "持有" +``` + +**Diagram sources** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) + +**Section sources** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) + +## Livy集成配置 +Livy是Spark的REST接口服务,允许通过HTTP请求提交和管理Spark作业。DataVines通过`AbstractLivyEngineExecutor`类集成Livy,实现对Spark作业的远程提交和管理。 + +Livy状态管理通过`LivyStates`类实现,该类定义了Livy会话的各种状态,包括NOT_STARTED、STARTING、IDLE、RUNNING、BUSY、ERROR、DEAD、KILLED、SUCCESS等。执行器通过查询Livy REST API获取作业状态,并根据状态进行相应的处理。 + +```mermaid +classDiagram +class LivyStates { ++State NOT_STARTED ++State STARTING ++State IDLE ++State RUNNING ++State BUSY ++State ERROR ++State DEAD ++State KILLED ++State SUCCESS ++State UNKNOWN ++toLivyState(Map object) ++isActive(State state) ++isHealthy(State state) +} +class LivyCommandProcess { ++submitJob() ++getJobStatus() ++cancel() ++processResultOfLivyState(Object result, ProcessResult processResult) +} +class LivyEngineExecutor { ++buildCommand() ++execute() ++cancel() +} +LivyEngineExecutor --> LivyCommandProcess : "使用" +LivyCommandProcess --> LivyStates : "转换状态" +``` + +**Diagram sources** +- [LivyStates.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java) + +**Section sources** +- [LivyStates.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) + +## 执行参数与资源分配 +执行参数和资源分配通过`SparkEngineParameter`类进行配置。该类定义了Spark作业的各种参数,包括程序类型、部署模式、驱动程序核心数、驱动程序内存、执行器数量、每个执行器的核心数、每个执行器的内存等。 + +这些参数在提交Spark作业时作为命令行参数传递给Spark-submit脚本,用于控制作业的资源分配和执行行为。 + +```mermaid +classDiagram +class SparkEngineParameter { ++String programType ++String deployMode ++int driverCores ++String driverMemory ++int numExecutors ++int executorCores ++String executorMemory ++String others +} +class SparkRuntimeEnvironment { ++prepare() ++createSparkConf() +} +SparkRuntimeEnvironment --> SparkEngineParameter : "使用参数" +SparkRuntimeEnvironment --> SparkConf : "创建配置" +``` + +**Diagram sources** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) + +**Section sources** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) + +## 执行模式与超时设置 +执行模式通过配置参数进行设置,支持批处理和流处理两种模式。批处理模式适用于一次性处理大量数据,而流处理模式适用于持续处理实时数据流。 + +超时设置通过作业配置中的超时策略进行管理。系统提供了多种超时策略,包括固定超时、动态超时等。当作业执行时间超过设定的超时阈值时,系统会自动终止作业并记录超时信息。 + +执行模式和超时设置在`RuntimeEnvironment`接口中定义,具体的执行器实现类根据配置创建相应的执行环境。 + +**Section sources** +- [RuntimeEnvironment.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java) +- [Execution.java](file://datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/Execution.java) + +## JVM参数与内存配置 +JVM参数和内存配置通过Spark和Flink的配置系统进行管理。对于Spark执行引擎,JVM参数通过SparkConf进行设置;对于Flink执行引擎,JVM参数通过StreamExecutionEnvironment进行设置。 + +内存配置包括堆内存和非堆内存的分配。系统建议根据数据规模和处理需求合理配置内存,避免内存溢出或资源浪费。对于大规模数据处理,建议增加堆内存大小,并配置适当的GC策略。 + +JVM参数和内存配置还可以通过环境变量或配置文件进行设置,以便在不同环境中灵活调整。 + +**Section sources** +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) +- [FlinkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java) + +## 执行状态监控 +执行状态监控通过日志和状态查询两种方式实现。系统会记录详细的执行日志,包括作业提交、执行进度、完成状态等信息。同时,系统还提供了状态查询接口,可以实时获取作业的执行状态。 + +对于分布式执行引擎,系统通过查询资源调度平台(如Yarn、Livy)的REST API获取作业状态。监控信息包括作业ID、应用ID、执行状态、资源使用情况等。 + +执行状态监控还支持告警功能,当作业执行失败或超时时,系统会触发告警并通知相关人员。 + +**Section sources** +- [AbstractEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java) +- [LivyStates.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/LivyStates.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\346\234\254\345\234\260\346\211\247\350\241\214\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\346\234\254\345\234\260\346\211\247\350\241\214\351\205\215\347\275\256.md" new file mode 100644 index 00000000..d863be14 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\346\234\254\345\234\260\346\211\247\350\241\214\351\205\215\347\275\256.md" @@ -0,0 +1,303 @@ +# 本地执行配置 + + +**本文档引用的文件** +- [BaseLocalConfigurationBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/BaseLocalConfigurationBuilder.java) +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [LocalDataVinesBootstrap.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) +- [LocalRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java) +- [LocalExecution.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalExecution.java) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) +- [ThreadUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ThreadUtils.java) + + +## 目录 +1. [简介](#简介) +2. [本地执行环境初始化](#本地执行环境初始化) +3. [JVM配置与内存管理](#jvm配置与内存管理) +4. [线程池设置](#线程池设置) +5. [BaseLocalConfigurationBuilder配置构建](#baselocalconfigurationbuilder配置构建) +6. [LocalEngineExecutor任务执行](#localengineexecutor任务执行) +7. [适用场景与性能特点](#适用场景与性能特点) +8. [配置最佳实践](#配置最佳实践) +9. [本地执行任务调试](#本地执行任务调试) +10. [总结](#总结) + +## 简介 +DataVines本地执行模式是一种在单机环境中运行数据质量验证任务的执行方式。该模式适用于开发测试、小规模数据验证和快速原型验证等场景。本地执行模式通过BaseLocalConfigurationBuilder类构建执行配置,并由LocalEngineExecutor处理任务的执行。本文档将详细介绍本地执行模式的配置方法,包括环境初始化参数、JVM配置、内存管理、线程池设置等关键配置项,以及如何调试本地执行任务。 + +## 本地执行环境初始化 +本地执行环境的初始化主要通过LocalEngineExecutor类的init方法完成。该方法接收JobExecutionRequest、Logger和Configurations三个参数,用于初始化本地执行环境。 + +初始化过程包括: +1. 记录本地引擎初始化日志 +2. 设置当前线程名称,便于日志追踪 +3. 保存任务执行请求和日志对象 + +```mermaid +flowchart TD +Start([开始初始化]) --> SetThreadName["设置线程名称为JOB_LOG_INFO_FORMAT格式"] +SetThreadName --> SaveRequest["保存JobExecutionRequest"] +SaveRequest --> SaveLogger["保存Logger对象"] +SaveLogger --> End([初始化完成]) +``` + +**本地执行环境初始化流程图** + +**Diagram sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L31-L38) + +**Section sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L31-L38) + +## JVM配置与内存管理 +DataVines本地执行模式的JVM配置主要通过系统属性和配置文件进行管理。关键的内存管理参数包括: + +- **最大CPU负载平均值**:通过`max.cpu.load.avg`配置项设置,默认值为0.5 +- **保留内存**:通过`reserved.memory`配置项设置,默认值为0.3G + +这些配置在CommonPropertyUtils类中定义,用于控制本地执行环境的资源使用: + +```java +public static final String MAX_CPU_LOAD_AVG = "max.cpu.load.avg"; +public static final Double MAX_CPU_LOAD_AVG_DEFAULT = 0.5; + +public static final String RESERVED_MEMORY = "reserved.memory"; +public static final Double RESERVED_MEMORY_DEFAULT = 0.3; +``` + +当系统检测到CPU负载过高或可用内存不足时,会拒绝执行任务以保护系统稳定性。 + +```mermaid +flowchart TD +CheckResource["检查系统资源"] --> CheckCPU["检查CPU负载"] +CheckCPU --> CPUHigh{"CPU负载 > max.cpu.load.avg?"} +CPUHigh --> |是| Reject["拒绝执行任务"] +CPUHigh --> |否| CheckMemory["检查可用内存"] +CheckMemory --> MemoryLow{"可用内存 < reserved.memory?"} +MemoryLow --> |是| Reject +MemoryLow --> |否| Accept["接受执行任务"] +Reject --> End1([任务被拒绝]) +Accept --> End2([任务被接受]) +``` + +**资源检查流程图** + +**Diagram sources** +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java#L38-L42) +- [OSUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/OSUtils.java#L429-L434) + +**Section sources** +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java#L38-L42) + +## 线程池设置 +DataVines本地执行模式使用线程池来管理并发执行的任务。线程池的配置主要通过ThreadUtils类实现,提供了创建守护线程池的方法。 + +关键的线程池配置方法包括: +- `newDaemonCachedThreadPool(String prefix)`:创建带前缀的守护线程池 +- `newDaemonCachedThreadPool(String prefix, int maxThreadNumber, int keepAliveSeconds)`:创建带最大线程数和存活时间的守护线程池 + +线程池配置参数: +- **核心线程池大小**:等于最大线程数 +- **最大线程池大小**:等于最大线程数 +- **线程存活时间**:可配置的秒数 +- **工作队列**:使用LinkedBlockingQueue +- **线程工厂**:使用命名线程工厂,线程名称格式为"prefix-ID" + +```mermaid +classDiagram +class ThreadPoolExecutor { ++int corePoolSize ++int maximumPoolSize ++long keepAliveTime ++TimeUnit unit ++BlockingQueue~Runnable~ workQueue ++ThreadFactory threadFactory +} +class ThreadFactory { ++String nameFormat ++boolean daemon +} +class LinkedBlockingQueue { ++int capacity +} +ThreadPoolExecutor --> ThreadFactory : "使用" +ThreadPoolExecutor --> LinkedBlockingQueue : "使用" +``` + +**线程池组件关系图** + +**Diagram sources** +- [ThreadUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ThreadUtils.java#L49-L87) + +**Section sources** +- [ThreadUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ThreadUtils.java#L49-L87) + +## BaseLocalConfigurationBuilder配置构建 +BaseLocalConfigurationBuilder是本地执行配置的核心构建类,负责构建本地执行所需的环境配置、数据源配置、转换配置和接收器配置。 + +### 配置构建流程 +1. **环境配置构建**:通过getEnvConfig方法构建环境配置 +2. **数据源配置构建**:通过getSourceConfigs方法构建数据源配置 +3. **转换配置构建**:通过buildTransformConfigs方法构建转换配置 +4. **接收器配置构建**:通过buildSinkConfigs方法构建接收器配置 + +```mermaid +sequenceDiagram +participant Builder as BaseLocalConfigurationBuilder +participant PluginLoader as PluginLoader +participant ConnectorFactory as ConnectorFactory +participant SqlMetric as SqlMetric +Builder->>Builder : getEnvConfig() +Builder->>Builder : getSourceConfigs() +activate Builder +loop 每个度量参数 +Builder->>PluginLoader : 加载SqlMetric插件 +PluginLoader-->>Builder : 返回SqlMetric实例 +Builder->>PluginLoader : 加载ConnectorFactory插件 +PluginLoader-->>Builder : 返回ConnectorFactory实例 +Builder->>SqlMetric : 获取SQL语句 +SqlMetric-->>Builder : 返回SQL语句 +Builder->>Builder : 构建数据源配置 +end +deactivate Builder +Builder->>Builder : buildTransformConfigs() +Builder->>Builder : buildSinkConfigs() +``` + +**配置构建序列图** + +**Diagram sources** +- [BaseLocalConfigurationBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/BaseLocalConfigurationBuilder.java#L47-L333) + +**Section sources** +- [BaseLocalConfigurationBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/BaseLocalConfigurationBuilder.java#L47-L333) + +## LocalEngineExecutor任务执行 +LocalEngineExecutor是本地执行模式的核心执行器,负责执行本地任务。它继承自AbstractEngineExecutor,实现了execute方法来执行任务。 + +### 任务执行流程 +1. **初始化**:调用init方法初始化执行环境 +2. **执行**:调用execute方法执行任务 +3. **后续处理**:调用after方法进行后续处理 +4. **取消**:调用cancel方法取消任务 + +```mermaid +flowchart TD +Init["init方法初始化"] --> Execute["execute方法执行"] +Execute --> CreateArgs["创建参数数组"] +CreateArgs --> CreateBootstrap["创建LocalDataVinesBootstrap实例"] +CreateBootstrap --> ExecuteBootstrap["调用bootstrap.execute()"] +ExecuteBootstrap --> SetResult["设置processResult"] +SetResult --> After["after方法后续处理"] +After --> End([任务执行完成]) +Cancel["cancel方法取消"] --> CheckBootstrap["检查bootstrap是否为空"] +CheckBootstrap --> |不为空| StopBootstrap["调用bootstrap.stop()"] +StopBootstrap --> SetCancel["设置cancel标志"] +SetCancel --> End +``` + +**任务执行流程图** + +**Diagram sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L31-L77) + +**Section sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java#L31-L77) + +## 适用场景与性能特点 +### 适用场景 +1. **开发测试**:在开发环境中快速验证数据质量规则 +2. **小规模数据验证**:处理数据量较小的验证任务 +3. **快速原型验证**:快速验证新的数据质量规则或配置 +4. **单机环境**:在没有分布式集群的环境中运行 + +### 性能特点 +1. **低延迟**:由于在单机上运行,避免了网络通信开销 +2. **资源占用可控**:可以通过配置限制CPU和内存使用 +3. **启动速度快**:无需启动分布式集群,启动时间短 +4. **调试方便**:可以直接在开发环境中调试和查看日志 + +```mermaid +graph TD +A[本地执行模式] --> B[开发测试] +A --> C[小规模数据验证] +A --> D[快速原型验证] +A --> E[单机环境] +F[性能特点] --> G[低延迟] +F --> H[资源占用可控] +F --> I[启动速度快] +F --> J[调试方便] +``` + +**适用场景与性能特点关系图** + +**Diagram sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [BaseLocalConfigurationBuilder.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/BaseLocalConfigurationBuilder.java) + +## 配置最佳实践 +### JVM配置最佳实践 +1. **合理设置最大CPU负载**:根据服务器性能调整`max.cpu.load.avg`值 +2. **预留足够内存**:根据系统总内存设置`reserved.memory`值 +3. **监控系统资源**:定期检查CPU和内存使用情况 + +### 线程池配置最佳实践 +1. **合理设置线程数**:根据任务并发需求设置最大线程数 +2. **设置适当的存活时间**:避免线程长时间空闲占用资源 +3. **使用有意义的线程名称前缀**:便于日志追踪和问题排查 + +### 本地执行配置最佳实践 +1. **使用合适的配置构建器**:根据任务类型选择相应的配置构建器 +2. **正确配置数据源**:确保数据源连接信息正确无误 +3. **合理设置超时策略**:避免任务长时间运行影响系统稳定性 +4. **启用日志记录**:便于问题排查和性能分析 + +## 本地执行任务调试 +### 调试方法 +1. **日志调试**:通过日志文件查看任务执行过程 +2. **断点调试**:在开发环境中设置断点进行调试 +3. **参数验证**:验证配置参数的正确性 + +### 调试工具 +1. **日志系统**:使用Logback进行日志记录 +2. **线程监控**:使用ThreadMXBean监控线程状态 +3. **性能分析**:使用JVM工具分析性能瓶颈 + +```mermaid +flowchart TD +Debug["调试本地执行任务"] --> LogDebug["日志调试"] +LogDebug --> CheckLog["检查日志文件"] +CheckLog --> AnalyzeLog["分析日志内容"] +Debug --> BreakpointDebug["断点调试"] +BreakpointDebug --> SetBreakpoint["设置断点"] +SetBreakpoint --> StepThrough["逐步执行"] +Debug --> ParameterDebug["参数验证"] +ParameterDebug --> ValidateConfig["验证配置参数"] +ValidateConfig --> TestConnection["测试连接"] +AnalyzeLog --> End1([问题解决]) +StepThrough --> End2([问题解决]) +TestConnection --> End3([问题解决]) +``` + +**本地执行任务调试流程图** + +**Diagram sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +**Section sources** +- [LocalEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java) +- [BaseDataVinesBootstrap.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java) + +## 总结 +DataVines本地执行模式提供了一种简单高效的本地数据质量验证方式。通过BaseLocalConfigurationBuilder类构建执行配置,由LocalEngineExecutor处理任务执行。本地执行模式适用于开发测试、小规模数据验证等场景,具有低延迟、资源占用可控、启动速度快和调试方便等优点。 + +关键配置要点包括: +1. 合理设置JVM参数,控制CPU和内存使用 +2. 正确配置线程池,管理并发执行 +3. 使用合适的配置构建器,确保配置正确性 +4. 启用详细的日志记录,便于问题排查 + +通过遵循最佳实践和使用适当的调试方法,可以有效提高本地执行任务的稳定性和性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256/Livy\350\265\204\346\272\220\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256/Livy\350\265\204\346\272\220\351\205\215\347\275\256.md" new file mode 100644 index 00000000..7c5ddca1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256/Livy\350\265\204\346\272\220\351\205\215\347\275\256.md" @@ -0,0 +1,171 @@ +# Livy资源配置 + + +**本文档引用文件** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql) +- [common.properties](file://datavines-common\src\main\resources\common.properties) + + +## 目录 +1. [引言](#引言) +2. [Livy服务器配置](#livy服务器配置) +3. [会话参数与资源配额](#会话参数与资源配额) +4. [认证机制配置](#认证机制配置) +5. [Spark任务提交与状态跟踪](#spark任务提交与状态跟踪) +6. [最佳实践](#最佳实践) +7. [结论](#结论) + +## 引言 + +DataVines是一个数据质量平台,通过集成Livy服务实现Spark任务的远程提交和管理。Livy作为Apache Spark的REST接口服务,允许用户通过HTTP请求与Spark集群进行交互。本文档详细说明DataVines与Livy服务集成的配置方法,包括Livy服务器地址配置、会话参数设置、资源配额管理、认证机制等。同时,解释AbstractLivyEngineExecutor和LivyTaskSubmitHelper如何实现Spark任务在Livy上的提交和状态跟踪。 + +## Livy服务器配置 + +DataVines通过配置Livy服务器地址来实现与Livy服务的集成。Livy服务器地址配置是集成的基础,决定了DataVines与Livy服务的通信路径。 + +Livy服务器地址通过`livy.uri`配置项进行设置,该配置项指定了Livy服务的REST API端点。在DataVines中,该配置可以在数据库的`dv_config`表中进行设置,如`datavines-mysql.sql`文件中的示例所示: + +```sql +INSERT INTO `dv_config` VALUES ('14', '-1', 'livy.uri', 'http://localhost:8998/batches', '1', '1', '2023-09-05 21:02:38', '1', '2023-09-05 21:02:38'); +``` + +此配置将Livy服务器地址设置为`http://localhost:8998/batches`,这是Livy服务的默认端点。在生产环境中,应根据实际的Livy服务部署情况进行相应的配置。 + +**Section sources** +- [datavines-mysql.sql](file://scripts\sql\datavines-mysql.sql#L865) + +## 会话参数与资源配额 + +Livy会话参数和资源配额的配置对于优化Spark任务的执行至关重要。这些参数决定了Spark应用的资源分配和执行行为。 + +### 会话超时设置 + +会话超时设置是管理Livy会话生命周期的重要配置。虽然在当前代码中未直接体现会话超时的配置,但通过`LivyTaskSubmitHelper`类中的`SLEEP_TIME`常量(值为1000毫秒),可以推断出在轮询Livy会话状态时的等待时间。合理的会话超时设置可以避免资源的长时间占用,提高资源利用率。 + +### 资源监控 + +资源监控是确保Spark任务稳定运行的关键。通过配置合理的资源配额,可以防止单个任务占用过多资源,影响其他任务的执行。在Livy中,可以通过会话创建时的JSON配置来指定资源配额,如executor的数量、内存大小等。 + +**Section sources** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L45) + +## 认证机制配置 + +DataVines支持多种认证机制来确保与Livy服务通信的安全性,包括Basic Auth和Kerberos认证。 + +### Basic Auth + +Basic Auth是一种简单的认证机制,通过用户名和密码进行身份验证。在DataVines中,虽然没有直接体现Basic Auth的配置,但通过`LivyTaskSubmitHelper`类中的`REQUEST_BY_HEADER`常量(值为"X-Requested-By")和请求头设置,可以推断出支持通过HTTP头进行基本的身份验证。 + +### Kerberos认证 + +Kerberos认证是一种更安全的网络认证协议,广泛应用于企业级大数据平台。DataVines通过配置`livy.need.kerberos`、`livy.server.auth.kerberos.principal`和`livy.server.auth.kerberos.keytab`等参数来支持Kerberos认证。 + +```java +if (needKerberos.equalsIgnoreCase("false")) { + logger.info("The livy server doesn't need Kerberos Authentication"); + // Basic authentication or no authentication +} else { + logger.info("The livy server needs Kerberos Authentication"); + String userPrincipal = configurations.getString("livy.server.auth.kerberos.principal"); + String keyTabLocation = configurations.getString("livy.server.auth.kerberos.keytab"); + KerberosRestTemplate restTemplate = new KerberosRestTemplate(keyTabLocation, userPrincipal); + // Kerberos authentication +} +``` + +此代码片段展示了如何根据`livy.need.kerberos`配置项的值来决定是否启用Kerberos认证,并使用指定的principal和keytab文件进行认证。 + +**Section sources** +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L127-L164) + +## Spark任务提交与状态跟踪 + +DataVines通过`AbstractLivyEngineExecutor`和`LivyTaskSubmitHelper`类实现Spark任务在Livy上的提交和状态跟踪。 + +### AbstractLivyEngineExecutor + +`AbstractLivyEngineExecutor`是Livy引擎执行器的抽象基类,继承自`AbstractEngineExecutor`。它定义了Livy任务执行的基本框架,包括任务取消等操作。 + +```java +public abstract class AbstractLivyEngineExecutor extends AbstractEngineExecutor { + protected LivyCommandProcess livyCommandProcess; + + @Override + public void cancel() throws Exception { + livyCommandProcess.cancel(); + cancel = true; + } +} +``` + +此抽象类通过`livyCommandProcess`字段与具体的命令处理逻辑进行交互,实现了任务取消的功能。 + +### LivyTaskSubmitHelper + +`LivyTaskSubmitHelper`类是Livy任务提交的核心辅助类,负责与Livy REST API进行交互,实现任务的提交、状态查询和删除等操作。 + +```mermaid +classDiagram +class LivyTaskSubmitHelper { +-RestTemplate restTemplate +-String uri +-Configurations configurations ++LivyTaskSubmitHelper(Configurations configurations) ++void init() ++String postToLivy(String livyArgs) ++String getFromLivy(String uri) ++void deleteByLivy(Long sessionId, String appId) ++void deleteByYarn(String url, String appId) +} +class AbstractLivyEngineExecutor { +-LivyCommandProcess livyCommandProcess ++void cancel() +} +class LivyCommandProcess { +-LivyTaskSubmitHelper livyTaskSubmitHelper +-int appIdRetryCount ++Map~String, Object~ post2LivyWithRetry(String livyArgs) ++boolean processResultOfLivyState(Object sessionId, ProcessResult processResult) +} +LivyCommandProcess --> LivyTaskSubmitHelper : "uses" +AbstractLivyEngineExecutor --> LivyCommandProcess : "contains" +``` + +**Diagram sources ** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java#L23-L36) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L38-L143) + +**Section sources** +- [AbstractLivyEngineExecutor.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\base\AbstractLivyEngineExecutor.java#L23-L36) +- [LivyTaskSubmitHelper.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\helper\LivyTaskSubmitHelper.java#L39-L257) +- [LivyCommandProcess.java](file://datavines-engine\datavines-engine-executor\src\main\java\io\datavines\engine\executor\core\executor\LivyCommandProcess.java#L38-L143) + +## 最佳实践 + +### 高可用部署方案 + +为了确保Livy服务的高可用性,建议采用以下部署方案: + +1. **集群部署**:将Livy服务部署在多个节点上,通过负载均衡器分发请求,避免单点故障。 +2. **ZooKeeper集成**:利用ZooKeeper实现Livy服务的注册与发现,自动处理节点故障和恢复。 +3. **定期健康检查**:配置定期的健康检查机制,及时发现并处理故障节点。 + +### 资源管理 + +1. **合理设置资源配额**:根据集群资源情况和任务需求,合理设置每个Spark应用的资源配额,避免资源浪费或不足。 +2. **动态资源分配**:启用Spark的动态资源分配功能,根据任务负载自动调整executor的数量,提高资源利用率。 + +### 安全性 + +1. **启用Kerberos认证**:在生产环境中,建议启用Kerberos认证,确保通信安全。 +2. **定期更新密钥**:定期更新Kerberos的keytab文件和principal,降低安全风险。 + +## 结论 + +DataVines通过集成Livy服务,实现了Spark任务的远程提交和管理。通过合理的配置,可以确保任务的高效、安全执行。本文档详细介绍了Livy资源配置的各个方面,包括服务器配置、会话参数、认证机制等,并解释了核心组件的工作原理。遵循本文档的最佳实践,可以构建一个稳定、高效的DataVines与Livy集成环境。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256/YARN\350\265\204\346\272\220\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256/YARN\350\265\204\346\272\220\351\205\215\347\275\256.md" new file mode 100644 index 00000000..63189c0b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256/YARN\350\265\204\346\272\220\351\205\215\347\275\256.md" @@ -0,0 +1,229 @@ +# YARN资源配置 + + +**本文档引用的文件** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) + + +## 目录 +1. [YARN资源配置](#yarn资源配置) +2. [YARN队列配置](#yarn队列配置) +3. [资源申请参数配置](#资源申请参数配置) +4. [高可用配置](#高可用配置) +5. [安全认证配置](#安全认证配置) +6. [AbstractYarnEngineExecutor实现分析](#abstractyarnengineexecutor实现分析) +7. [最佳实践](#最佳实践) + +## YARN队列配置 + +DataVines支持通过配置参数指定YARN队列,实现资源隔离和优先级管理。在Spark执行参数中,`queue`字段用于指定提交作业的目标队列。 + +通过合理配置YARN队列,可以实现不同租户、不同业务类型作业的资源隔离,避免资源争用。队列配置支持动态设置,可根据作业优先级、资源需求等因素选择合适的队列。 + +**Section sources** +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java#L75-L80) + +## 资源申请参数配置 + +DataVines提供了全面的资源申请参数配置,支持精细化的资源管理。主要资源配置参数包括: + +- **驱动程序资源**:`driverCores`和`driverMemory`参数用于配置驱动程序的核心数和内存 +- **执行器资源**:`numExecutors`、`executorCores`和`executorMemory`参数用于配置执行器的数量、核心数和内存 +- **应用程序名称**:`appName`参数用于设置应用程序名称,便于在YARN管理界面识别 +- **其他参数**:`others`参数用于传递额外的Spark配置参数 + +这些参数允许用户根据作业的计算复杂度和数据规模,精确配置所需的计算资源,优化资源利用率。 + +```mermaid +flowchart TD +A["资源配置参数"] --> B["驱动程序配置"] +A --> C["执行器配置"] +A --> D["队列配置"] +A --> E["其他配置"] +B --> B1["driverCores: 驱动核心数"] +B --> B2["driverMemory: 驱动内存"] +C --> C1["numExecutors: 执行器数量"] +C --> C2["executorCores: 执行器核心数"] +C --> C3["executorMemory: 执行器内存"] +D --> D1["queue: YARN队列"] +E --> E1["others: 其他参数"] +E --> E2["appName: 应用名称"] +``` + +**Diagram sources** +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java#L50-L75) + +**Section sources** +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java#L50-L80) + +## 高可用配置 + +DataVines支持YARN高可用配置,确保在ResourceManager故障时作业能够继续运行。高可用配置主要通过以下参数实现: + +- `yarn.mode`:配置YARN模式,支持"none"、"ha"和"standalone"三种模式 +- `yarn.resource.manager.ha.ids`:在HA模式下,配置ResourceManager的ID列表 +- `yarn.application.status.address`:配置应用程序状态查询地址 +- `yarn.resource.manager.http.address.port`:配置ResourceManager HTTP服务端口 + +当配置为HA模式时,系统会自动检测Active状态的ResourceManager,并向其提交作业,实现故障自动转移。 + +```mermaid +graph TB +A["YARN高可用配置"] --> B["模式配置"] +A --> C["ResourceManager配置"] +A --> D["状态查询配置"] +B --> B1["yarn.mode: HA模式"] +C --> C1["yarn.resource.manager.ha.ids"] +C --> C2["ACTIVE/STANDBY状态检测"] +D --> D1["yarn.application.status.address"] +D --> D2["HTTP端口配置"] +C2 --> |ACTIVE| E["作业提交"] +C2 --> |STANDBY| F["状态同步"] +``` + +**Diagram sources** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L33-L44) + +**Section sources** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L33-L47) + +## 安全认证配置 + +DataVines支持Kerberos安全认证,确保与YARN集群的安全通信。Kerberos认证配置主要涉及以下方面: + +- **Kerberos初始化**:通过`initKerberos`方法使用keytab文件和principal进行认证 +- **配置检查**:验证keytab principal、keytab文件路径和krb5配置文件的完整性 +- **Principal提取**:从keytab文件中提取可用的principal列表 + +在Livy集成场景中,系统会根据配置自动选择是否启用Kerberos认证,并使用相应的RestTemplate进行安全通信。 + +```mermaid +sequenceDiagram +participant Client as "DataVines客户端" +participant Kerberos as "Kerberos认证" +participant YARN as "YARN集群" +Client->>Kerberos : initKerberos(keytabPrincipal, keytabPath, krb5Config) +Kerberos-->>Client : 认证结果 +alt 认证成功 +Client->>YARN : 提交作业(携带认证信息) +YARN-->>Client : 作业提交成功 +else 认证失败 +Client->>Client : 记录错误日志 +end +``` + +**Diagram sources** +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java#L39-L76) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L127-L190) + +**Section sources** +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java#L39-L76) + +## AbstractYarnEngineExecutor实现分析 + +`AbstractYarnEngineExecutor`是DataVines中YARN任务提交和状态监控的核心实现类。该类继承自`AbstractEngineExecutor`,提供了YARN特定的功能实现。 + +### 任务提交与取消 + +`AbstractYarnEngineExecutor`通过`ShellCommandProcess`执行YARN命令来提交和管理作业。当需要取消作业时,会调用`cancel`方法,该方法会: + +1. 设置取消标志 +2. 取消底层进程 +3. 调用`killYarnApplication`方法终止YARN应用程序 + +### 状态监控机制 + +系统通过`YarnUtils`工具类实现YARN应用程序的状态监控。主要方法包括: + +- `getApplicationStatus`:通过HTTP接口查询应用程序的最终状态 +- `isSuccessOfYarnState`:轮询检查应用程序状态,直到完成或失败 +- `getYarnAppId`:根据租户代码和作业执行唯一ID生成YARN应用ID + +状态监控采用轮询机制,在作业执行期间定期检查YARN应用程序状态,并将状态更新反馈给作业管理系统。 + +```mermaid +classDiagram +class AbstractYarnEngineExecutor { +-ShellCommandProcess shellCommandProcess ++cancel() +-killYarnApplication() +} +class AbstractEngineExecutor { ++execute() ++cancel() ++getProcessResult() +} +class YarnUtils { ++isYarnEnabled() ++getApplicationStatus(applicationId) ++isSuccessOfYarnState(appId) ++getYarnAppId(tenantCode, jobExecutionUniqueId) +} +class ShellCommandProcess { ++run(executeCommand) ++cancel() +} +AbstractYarnEngineExecutor --|> AbstractEngineExecutor : 继承 +AbstractYarnEngineExecutor --> ShellCommandProcess : 使用 +AbstractYarnEngineExecutor --> YarnUtils : 使用 +``` + +**Diagram sources** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L40) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L194-L269) +- [BaseCommandProcess.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/executor/BaseCommandProcess.java#L76-L109) + +**Section sources** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L40) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L194-L269) + +## 最佳实践 + +### 资源隔离策略 + +1. **队列规划**:根据业务重要性、作业类型和资源需求,合理规划YARN队列 +2. **资源配额**:为不同队列设置适当的资源配额,避免资源过度集中 +3. **优先级管理**:通过队列优先级配置,确保关键作业获得足够的资源 + +### 队列选择策略 + +1. **基于作业类型**:将批处理作业、实时作业和交互式查询分配到不同的队列 +2. **基于数据规模**:根据处理数据量大小选择合适的队列 +3. **基于SLA要求**:对有严格SLA要求的作业分配高优先级队列 + +### 故障恢复机制 + +1. **状态持久化**:定期保存作业执行状态,支持故障后恢复 +2. **重试策略**:对临时性故障实现自动重试,提高作业成功率 +3. **监控告警**:建立完善的监控告警体系,及时发现和处理异常 + +4. **优雅终止**:在作业取消时,确保资源被正确释放,避免资源泄漏 + +```mermaid +flowchart TD +A["资源配置最佳实践"] --> B["资源隔离"] +A --> C["队列选择"] +A --> D["故障恢复"] +B --> B1["队列规划"] +B --> B2["资源配额"] +B --> B3["优先级管理"] +C --> C1["作业类型"] +C --> C2["数据规模"] +C --> C3["SLA要求"] +D --> D1["状态持久化"] +D --> D2["重试策略"] +D --> D3["监控告警"] +D --> D4["优雅终止"] +``` + +**Diagram sources** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L242-L265) +- [JobExecutionFailover.java](file://datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java#L119-L142) + +**Section sources** +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L242-L265) +- [FlinkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java#L151-L167) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256.md" new file mode 100644 index 00000000..62e1845e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\211\247\350\241\214\345\274\225\346\223\216\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256/\350\265\204\346\272\220\350\260\203\345\272\246\351\205\215\347\275\256.md" @@ -0,0 +1,289 @@ +# 资源调度配置 + + +**本文档引用的文件** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) + + +## 目录 +1. [引言](#引言) +2. [资源调度平台类型](#资源调度平台类型) +3. [YARN调度模式](#yarn调度模式) +4. [Livy调度模式](#livy调度模式) +5. [调度平台集成实现](#调度平台集成实现) +6. [资源调度配置最佳实践](#资源调度配置最佳实践) +7. [总结](#总结) + +## 引言 +DataVines支持多种资源调度平台,主要包括YARN和Livy两种模式。本文档详细说明了这两种调度模式的配置方法、连接方式、认证机制和资源管理策略。通过分析ResourceSchedulePlatformType枚举定义的调度类型,以及AbstractYarnEngineExecutor和LivyTaskSubmitHelper如何实现不同调度平台的集成,为用户提供完整的资源调度配置指导。 + +## 资源调度平台类型 +DataVines通过ResourceSchedulePlatformType枚举定义了支持的资源调度平台类型,这些类型决定了任务提交和资源管理的方式。 + +```mermaid +classDiagram +class ResourceSchedulePlatformType { ++LOCAL(0,"local") ++YARN(1,"yarn") ++K8S(2,"k8s") ++of(int) ResourceSchedulePlatformType ++of(String) ResourceSchedulePlatformType ++getCode() int ++getDescription() String +} +``` + +**图源** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java#L19-L60) + +ResourceSchedulePlatformType枚举包含以下三种调度平台类型: +- **LOCAL**:本地模式,代码值为0,描述为"local" +- **YARN**:YARN模式,代码值为1,描述为"yarn" +- **K8S**:Kubernetes模式,代码值为2,描述为"k8s" + +该枚举提供了静态方法of()用于根据代码值或描述字符串获取对应的枚举实例,以及getCode()和getDescription()方法用于获取枚举的代码值和描述信息。 + +**本节来源** +- [ResourceSchedulePlatformType.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java#L19-L60) + +## YARN调度模式 +YARN调度模式通过AbstractYarnEngineExecutor抽象类和具体的SparkEngineExecutor实现类来完成任务的提交和管理。 + +### 配置参数 +YARN调度模式支持以下主要配置参数: +- **driver-cores**:Driver使用的CPU核心数 +- **driver-memory**:Driver使用的内存大小 +- **num-executors**:启动的Executor数量 +- **executor-cores**:每个Executor使用的CPU核心数 +- **executor-memory**:每个Executor使用的内存大小 +- **app name**:应用程序名称 +- **queue**:提交到的YARN队列 +- **other arguments**:其他参数 + +### 连接方式 +YARN调度通过命令行方式连接,使用spark-submit命令提交任务。在SparkEngineExecutor中,通过构建包含所有必要参数的命令字符串来实现任务提交。 + +### 认证机制 +YARN调度模式支持通过Hadoop的认证机制进行安全访问。在YarnUtils类中,可以通过配置yarn.mode参数来指定YARN模式(单机模式、HA模式或不使用资源管理器)。 + +### 资源管理 +YARN调度模式的资源管理主要通过以下方式实现: +- 通过queue参数指定任务提交到的YARN队列,实现资源隔离和优先级管理 +- 通过num-executors、executor-cores和executor-memory参数精确控制资源分配 +- 通过spark.yarn.tags参数为每个任务添加唯一标识,便于资源追踪和管理 + +```mermaid +sequenceDiagram +participant SparkEngineExecutor as SparkEngineExecutor +participant ShellCommandProcess as ShellCommandProcess +participant YARN as YARN集群 +SparkEngineExecutor->>SparkEngineExecutor : buildCommand() +SparkEngineExecutor->>ShellCommandProcess : run(command) +ShellCommandProcess->>YARN : 执行spark-submit命令 +YARN-->>ShellCommandProcess : 返回执行结果 +ShellCommandProcess-->>SparkEngineExecutor : 返回ProcessResult +SparkEngineExecutor->>SparkEngineExecutor : cancel() +SparkEngineExecutor->>YARN : yarn application -kill [applicationId] +``` + +**图源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L153) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) + +**本节来源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L153) +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L37-L80) + +## Livy调度模式 +Livy调度模式通过AbstractLivyEngineExecutor抽象类和LivyTaskSubmitHelper辅助类来实现与Livy服务器的交互。 + +### 配置参数 +Livy调度模式支持以下主要配置参数: +- **livy.uri**:Livy服务器的URI地址 +- **livy.need.kerberos**:是否需要Kerberos认证 +- **livy.server.auth.kerberos.principal**:Kerberos认证的主体 +- **livy.server.auth.kerberos.keytab**:Kerberos认证的keytab文件位置 +- **livy.task.proxyUser**:代理用户 +- **livy.task.jar.lib.path**:JAR库的HDFS路径 +- **livy.task.jars**:额外的JAR文件 + +### 连接方式 +Livy调度通过REST API方式连接,使用HTTP POST请求向Livy服务器提交任务。LivyTaskSubmitHelper类封装了与Livy服务器通信的所有细节。 + +### 认证机制 +Livy调度模式支持两种认证机制: +- **非Kerberos认证**:当livy.need.kerberos配置为false时,使用普通HTTP认证 +- **Kerberos认证**:当livy.need.kerberos配置为true时,使用Kerberos认证,需要提供principal和keytab文件 + +### 资源管理 +Livy调度模式的资源管理主要通过以下方式实现: +- 通过queue参数指定任务提交到的YARN队列 +- 通过num-executors、executor-cores和executor-memory参数控制资源分配 +- 通过proxyUser参数指定代理用户,实现多租户资源隔离 +- 通过Livy的会话管理功能实现任务的生命周期管理 + +```mermaid +sequenceDiagram +participant LivyEngineExecutor as LivyEngineExecutor +participant LivyTaskSubmitHelper as LivyTaskSubmitHelper +participant LivyServer as Livy服务器 +LivyEngineExecutor->>LivyEngineExecutor : buildCommand() +LivyEngineExecutor->>LivyTaskSubmitHelper : postToLivy(livyArgs) +LivyTaskSubmitHelper->>LivyServer : POST /batches +LivyServer-->>LivyTaskSubmitHelper : 返回会话ID +LivyTaskSubmitHelper->>LivyEngineExecutor : 返回结果 +LivyEngineExecutor->>LivyEngineExecutor : execute() +LivyEngineExecutor->>LivyTaskSubmitHelper : getResultByLivyId(sessionId) +LivyTaskSubmitHelper->>LivyServer : GET /batches/[sessionId] +LivyServer-->>LivyTaskSubmitHelper : 返回执行状态 +LivyTaskSubmitHelper-->>LivyEngineExecutor : 返回状态信息 +``` + +**图源** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java#L42-L237) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L39-L258) + +**本节来源** +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java#L42-L237) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L39-L258) + +## 调度平台集成实现 +DataVines通过抽象基类和具体实现类的组合模式实现了不同调度平台的集成,确保了代码的可扩展性和可维护性。 + +### AbstractYarnEngineExecutor实现 +AbstractYarnEngineExecutor是YARN调度模式的抽象基类,提供了任务取消和YARN应用终止的通用实现。 + +```mermaid +classDiagram +class AbstractYarnEngineExecutor { +-shellCommandProcess ShellCommandProcess ++cancel() void +-killYarnApplication() void +} +class AbstractEngineExecutor { +#jobExecutionRequest JobExecutionRequest +#logger Logger +#processResult ProcessResult +#cancel boolean ++init(JobExecutionRequest, Logger, Configurations) void ++execute() void ++after() void ++getProcessResult() ProcessResult ++getTaskRequest() JobExecutionRequest +-logHandle(String) void +-buildCommand() String +} +AbstractYarnEngineExecutor --|> AbstractEngineExecutor +AbstractYarnEngineExecutor --> ShellCommandProcess +``` + +**图源** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) + +### LivyTaskSubmitHelper实现 +LivyTaskSubmitHelper是Livy调度模式的核心辅助类,负责与Livy服务器的所有交互操作。 + +```mermaid +classDiagram +class LivyTaskSubmitHelper { +-restTemplate RestTemplate +-uri String +-configurations Configurations ++init() void ++retryLivyGetAppId(String, int) Map~String, Object~ ++getResultByLivyId(Object, TypeReference) Map~String, Object~ ++postToLivy(String) String ++getFromLivy(String) String ++deleteByLivy(Long, String) void ++deleteByLivy(String) void ++deleteByYarn(String, String) void +} +LivyTaskSubmitHelper --> RestTemplate +LivyTaskSubmitHelper --> Configurations +LivyTaskSubmitHelper --> KerberosRestTemplate +``` + +**图源** +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L39-L258) + +### 继承关系与实现 +DataVines的调度平台集成采用了清晰的继承层次结构,确保了不同调度模式的实现既保持一致性又具有灵活性。 + +```mermaid +classDiagram +class AbstractEngineExecutor { +<> +} +class AbstractYarnEngineExecutor { +<> +} +class AbstractLivyEngineExecutor { +<> +} +class SparkEngineExecutor { +} +class LivyEngineExecutor { +} +AbstractEngineExecutor <|-- AbstractYarnEngineExecutor +AbstractEngineExecutor <|-- AbstractLivyEngineExecutor +AbstractYarnEngineExecutor <|-- SparkEngineExecutor +AbstractLivyEngineExecutor <|-- LivyEngineExecutor +``` + +**图源** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java#L23-L37) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L153) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java#L42-L237) + +**本节来源** +- [AbstractYarnEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java#L25-L60) +- [AbstractLivyEngineExecutor.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java#L23-L37) +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L153) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java#L42-L237) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L39-L258) + +## 资源调度配置最佳实践 +为了确保DataVines在生产环境中的稳定运行和高效资源利用,以下是一些资源调度配置的最佳实践。 + +### 队列选择 +- **生产环境**:为生产任务配置专用的高优先级队列,确保关键任务的资源保障 +- **开发环境**:为开发和测试任务配置低优先级队列,避免影响生产任务 +- **多租户环境**:为不同租户配置独立的队列,实现资源隔离和配额管理 + +### 资源配额 +- **Driver资源**:根据任务复杂度合理配置Driver的CPU核心数和内存大小,避免资源浪费 +- **Executor资源**:根据数据量和计算复杂度配置Executor数量、核心数和内存大小 +- **动态调整**:根据任务历史执行情况动态调整资源配额,优化资源利用率 + +### 高可用配置 +- **YARN HA模式**:在生产环境中启用YARN的高可用模式,配置多个ResourceManager +- **Livy高可用**:部署多个Livy服务器,通过负载均衡实现高可用 +- **故障转移**:配置合理的重试机制和超时策略,确保任务在节点故障时能够自动恢复 + +### 安全配置 +- **Kerberos认证**:在生产环境中启用Kerberos认证,确保集群安全 +- **SSL/TLS**:配置HTTPS连接,保护数据传输安全 +- **权限控制**:通过代理用户和队列权限控制,实现细粒度的访问控制 + +### 监控与告警 +- **资源监控**:监控YARN队列的资源使用情况,及时发现资源瓶颈 +- **任务监控**:监控任务的执行状态和性能指标,及时发现异常任务 +- **告警配置**:配置合理的告警阈值,及时通知运维人员处理异常情况 + +**本节来源** +- [SparkEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java#L41-L153) +- [LivyEngineExecutor.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java#L42-L237) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L39-L258) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L37-L80) + +## 总结 +DataVines通过灵活的架构设计支持多种资源调度平台,包括YARN和Livy模式。通过ResourceSchedulePlatformType枚举定义调度类型,使用AbstractYarnEngineExecutor和AbstractLivyEngineExecutor抽象基类实现不同调度平台的集成。YARN模式通过命令行方式提交任务,适合对资源控制要求严格的场景;Livy模式通过REST API方式提交任务,适合需要细粒度会话管理和多租户支持的场景。通过合理的队列选择、资源配额、高可用配置和安全策略,可以确保DataVines在生产环境中的稳定运行和高效资源利用。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\346\200\247\350\203\275\350\260\203\344\274\230.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\346\200\247\350\203\275\350\260\203\344\274\230.md" new file mode 100644 index 00000000..2d81493d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\346\200\247\350\203\275\350\260\203\344\274\230.md" @@ -0,0 +1,221 @@ +# 数据库性能调优 + + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml) +- [JobExecutionResultMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionResultMapper.xml) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml) +- [DefaultDataSourceInfoUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/DefaultDataSourceInfoUtils.java) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [MetricLevel.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricLevel.java) +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java) +- [SqlUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/SqlUtils.java) + + +## 目录 +1. [引言](#引言) +2. [索引优化策略](#索引优化策略) +3. [查询优化技巧](#查询优化技巧) +4. [缓存策略与配置](#缓存策略与配置) +5. [数据库连接池调优](#数据库连接池调优) +6. [性能监控与基准测试](#性能监控与基准测试) +7. [常见性能瓶颈解决方案](#常见性能瓶颈解决方案) +8. [结论](#结论) + +## 引言 + +DataVines是一个数据质量监控平台,其核心功能依赖于高效的数据库操作。本文档深入探讨DataVines的数据库性能调优策略,涵盖索引优化、查询优化、缓存策略、连接池调优、性能监控和常见性能问题的解决方案。通过分析DataVines的数据库设计和配置,我们可以为类似的大数据应用提供性能优化的参考。 + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +## 索引优化策略 + +DataVines的数据库设计中包含了多个关键的索引,这些索引对于提高查询性能至关重要。通过分析`datavines-mysql.sql`文件,我们可以识别出需要索引的字段和复合索引的设计。 + +### 需要索引的字段 + +1. **主键字段**:所有表的主键字段都自动创建了索引,这是数据库性能的基础。 +2. **外键字段**:如`dv_job_execution`表中的`job_id`字段,用于关联`dv_job`表,创建索引可以提高连接查询的性能。 +3. **频繁查询的字段**:如`dv_job_execution`表中的`status`、`start_time`、`end_time`字段,这些字段经常用于查询条件,创建索引可以显著提高查询速度。 +4. **唯一性约束字段**:如`dv_datasource`表中的`name`字段,创建唯一索引可以确保数据的唯一性,同时提高查询性能。 + +### 复合索引设计 + +复合索引是提高多条件查询性能的有效手段。DataVines中的复合索引设计如下: + +1. **`dv_job_execution`表的复合索引**: + - `IDX_QRTZ_T_NFT_ST`:`SCHED_NAME`、`TRIGGER_STATE`、`NEXT_FIRE_TIME`,用于提高调度查询的性能。 + - `IDX_QRTZ_T_NFT_MISFIRE`:`SCHED_NAME`、`MISFIRE_INSTR`、`NEXT_FIRE_TIME`,用于提高错误处理查询的性能。 + +2. **`dv_catalog_entity_instance`表的复合索引**: + - `datasource_fqn_status_un`:`datasource_id`、`fully_qualified_name`、`status`,用于提高实体实例查询的性能。 + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +## 查询优化技巧 + +查询优化是提高数据库性能的关键。DataVines通过合理的查询设计和分页策略来优化查询性能。 + +### 避免全表扫描 + +1. **使用索引**:确保查询条件中的字段都已创建索引,避免全表扫描。 +2. **优化查询条件**:尽量使用等值查询,避免使用`LIKE`、`IN`等可能导致全表扫描的操作。 + +### 合理使用分页 + +DataVines在查询大量数据时使用分页策略,避免一次性加载过多数据。例如,在`JobExecutionMapper.xml`中,通过`LIMIT`和`OFFSET`实现分页: + +```xml + +``` + +**本文档引用的文件** +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml) + +## 缓存策略与配置 + +缓存是提高数据库性能的重要手段。DataVines通过HikariCP连接池和MyBatis二级缓存来优化性能。 + +### HikariCP连接池配置 + +在`application.yaml`中,HikariCP连接池的配置如下: + +```yaml +spring: + datasource: + hikari: + connection-test-query: select 1 + minimum-idle: 5 + auto-commit: true + validation-timeout: 3000 + pool-name: datavines + maximum-pool-size: 50 + connection-timeout: 30000 + idle-timeout: 600000 + leak-detection-threshold: 0 + initialization-fail-timeout: 1 +``` + +这些配置确保了连接池的高效运行,避免了连接泄漏和超时问题。 + +### MyBatis二级缓存 + +DataVines使用MyBatis作为ORM框架,通过二级缓存来减少数据库访问。在`JobExecutionMapper.xml`中,通过``标签启用二级缓存: + +```xml + + + ... + +``` + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml) + +## 数据库连接池调优 + +数据库连接池的调优对性能有重要影响。DataVines通过HikariCP连接池的配置来优化性能。 + +### 连接池参数调优 + +1. **`maximum-pool-size`**:最大连接数,设置为50,确保在高并发情况下有足够的连接。 +2. **`minimum-idle`**:最小空闲连接数,设置为5,确保在低负载情况下有足够的连接。 +3. **`connection-timeout`**:连接超时时间,设置为30000毫秒,避免长时间等待连接。 +4. **`idle-timeout`**:空闲超时时间,设置为600000毫秒,避免连接长时间空闲。 + +这些参数的合理配置可以确保连接池的高效运行,避免连接泄漏和超时问题。 + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 性能监控与基准测试 + +性能监控和基准测试是确保数据库性能的重要手段。DataVines通过日志和监控工具来监控数据库性能。 + +### 性能监控指标 + +1. **查询响应时间**:监控每个查询的响应时间,确保在合理范围内。 +2. **连接池使用率**:监控连接池的使用率,确保在高并发情况下有足够的连接。 +3. **数据库CPU和内存使用率**:监控数据库的CPU和内存使用率,确保资源充足。 + +### 基准测试方法 + +1. **压力测试**:通过模拟高并发请求,测试数据库的性能极限。 +2. **查询性能测试**:通过执行典型的查询,测试查询的响应时间。 +3. **连接池性能测试**:通过模拟连接池的使用,测试连接池的性能。 + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 常见性能瓶颈解决方案 + +在实际使用中,可能会遇到各种性能瓶颈。以下是常见的性能瓶颈及其解决方案。 + +### 全表扫描 + +**问题**:查询条件中的字段未创建索引,导致全表扫描。 +**解决方案**:为查询条件中的字段创建索引,避免全表扫描。 + +### 连接池耗尽 + +**问题**:高并发情况下,连接池中的连接被耗尽。 +**解决方案**:增加`maximum-pool-size`的值,确保在高并发情况下有足够的连接。 + +### 查询响应时间过长 + +**问题**:查询响应时间过长,影响用户体验。 +**解决方案**:优化查询条件,使用索引,避免全表扫描。 + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +## 结论 + +通过分析DataVines的数据库设计和配置,我们可以得出以下结论: + +1. **索引优化**:合理创建索引和复合索引,可以显著提高查询性能。 +2. **查询优化**:避免全表扫描,合理使用分页,可以提高查询效率。 +3. **缓存策略**:通过HikariCP连接池和MyBatis二级缓存,可以减少数据库访问,提高性能。 +4. **连接池调优**:合理配置连接池参数,可以确保连接池的高效运行。 +5. **性能监控**:通过监控和基准测试,可以及时发现和解决性能问题。 + +这些策略和方法可以为类似的大数据应用提供性能优化的参考。 + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [JobExecutionMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionMapper.xml) +- [JobExecutionResultMapper.xml](file://datavines-server/src/main/resources/mapper/JobExecutionResultMapper.xml) +- [DataSourceMapper.xml](file://datavines-server/src/main/resources/mapper/DataSourceMapper.xml) +- [DefaultDataSourceInfoUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/DefaultDataSourceInfoUtils.java) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java) +- [MetricType.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricType.java) +- [MetricLevel.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricLevel.java) +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java) +- [SqlUtils.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/SqlUtils.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\347\256\241\347\220\206.md" new file mode 100644 index 00000000..f5568732 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\347\256\241\347\220\206.md" @@ -0,0 +1,241 @@ +# 数据库管理 + + +**本文档引用的文件** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java) +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) + + +## 目录 +1. [数据库初始化](#数据库初始化) +2. [数据库迁移与版本管理](#数据库迁移与版本管理) +3. [备份与恢复方案](#备份与恢复方案) +4. [数据库安全管理](#数据库安全管理) +5. [日常维护与监控](#日常维护与监控) + +## 数据库初始化 + +DataVines的数据库初始化通过执行`datavines-mysql.sql`脚本完成,该脚本创建了系统所需的所有表结构和初始数据。脚本包含了Quartz调度框架所需的表结构以及DataVines核心功能的表结构。 + +数据库初始化脚本创建了以下主要表结构: +- **Quartz调度表**:包括`QRTZ_JOB_DETAILS`、`QRTZ_TRIGGERS`、`QRTZ_FIRED_TRIGGERS`等,用于任务调度管理 +- **数据质量规则表**:`dv_job`表存储规则作业定义,`dv_job_schedule`表存储作业调度信息 +- **元数据目录表**:`dv_catalog_entity_instance`表存储实体实例,`dv_catalog_entity_rel`表存储实体关系 +- **执行结果表**:`dv_job_execution_result`表存储规则执行结果,`dv_actual_values`表存储实际值 +- **数据源管理表**:`dv_datasource`表存储数据源配置,`dv_error_data_storage`表存储错误数据存储配置 +- **告警管理表**:`dv_sla`表存储SLA配置,`dv_sla_notification`表存储通知配置 + +数据库初始化过程中,系统会自动创建这些表结构,并设置适当的索引和外键约束以确保数据完整性。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L893) + +## 数据库迁移与版本管理 + +DataVines实现了完善的数据库迁移和版本管理机制,通过元数据变更跟踪来安全地进行模式变更。系统能够自动检测和记录数据库、表和列级别的变更。 + +### 元数据变更跟踪 + +系统通过`CatalogMetaDataFetchExecutorImpl`类实现元数据变更跟踪,该类会定期从数据源获取元数据并与数据库中的记录进行比较,识别出新增、删除或修改的实体。 + +```mermaid +flowchart TD +Start([开始元数据抓取]) --> FetchDataSource["从数据源获取元数据"] +FetchDataSource --> CompareDB["与数据库记录比较"] +CompareDB --> CheckNew["检查新增实体"] +CheckNew --> |有新增| CreateEntity["创建新实体记录"] +CheckNew --> |无新增| CheckDeleted["检查删除实体"] +CheckDeleted --> |有删除| DeleteEntity["软删除实体记录"] +CheckDeleted --> |无删除| CheckModified["检查修改实体"] +CheckModified --> |有修改| UpdateEntity["更新实体记录"] +UpdateEntity --> RecordChange["记录变更到dv_catalog_schema_change表"] +DeleteEntity --> RecordChange +CreateEntity --> RecordChange +RecordChange --> End([完成元数据同步]) +``` + +**Diagram sources ** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L143-L366) + +### 变更类型与记录 + +系统定义了多种变更类型,并将所有变更记录在`dv_catalog_schema_change`表中,便于审计和追溯。变更类型包括: + +```mermaid +classDiagram +class SchemaChangeType { ++DATABASE_ADDED ++DATABASE_DELETED ++TABLE_ADDED ++TABLE_DELETED ++TABLE_COMMENT_CHANGE ++COLUMN_ADDED ++COLUMN_DELETED ++COLUMN_TYPE_CHANGE ++COLUMN_COMMENT_CHANGE +} +class CatalogSchemaChange { ++id ++parent_uuid ++entity_uuid ++change_type ++database_name ++table_name ++column_name ++change_before ++change_after ++update_by ++update_time +} +SchemaChangeType --> CatalogSchemaChange : "定义" +``` + +**Diagram sources ** +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java#L24-L73) +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java#L30-L37) + +当检测到模式变更时,系统会创建相应的变更记录,包括变更前后的详细信息,如列类型变更会记录`change_before`和`change_after`字段。 + +**Section sources** +- [CatalogMetaDataFetchExecutorImpl.java](file://datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutorImpl.java#L143-L461) +- [SchemaChangeType.java](file://datavines-server/src/main/java/io/datavines/server/enums/SchemaChangeType.java#L24-L73) +- [CatalogSchemaChange.java](file://datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java#L30-L37) + +## 备份与恢复方案 + +DataVines提供了完整的备份和恢复方案,确保数据安全和系统可靠性。 + +### 全量备份策略 + +系统建议定期进行全量备份,备份频率根据业务需求确定,通常为每日一次。全量备份包括: +- DataVines元数据库的所有表数据 +- 配置文件(application.yaml等) +- 日志文件(可选) + +### 增量备份策略 + +对于频繁变更的数据,建议实施增量备份策略: +- 交易数据:每小时备份一次 +- 日志数据:每天备份一次 +- 配置变更:实时备份或每15分钟备份一次 + +### 恢复流程 + +数据恢复流程如下: +1. 停止DataVines服务 +2. 恢复最新的全量备份 +3. 按时间顺序应用增量备份 +4. 验证数据完整性 +5. 启动DataVines服务 + +## 数据库安全管理 + +DataVines实施了多层次的数据库安全管理措施,确保数据安全和隐私保护。 + +### 权限控制 + +系统通过以下方式实现权限控制: +- 基于角色的访问控制(RBAC) +- 数据源级别的访问权限 +- 工作空间级别的隔离 +- 管理员和普通用户的权限分离 + +### 敏感数据保护 + +系统对敏感数据实施了严格的保护措施: + +```mermaid +flowchart TD +SensitiveData["敏感数据"] --> Password["密码字段"] +SensitiveData --> Connection["连接信息"] +Password --> Encryption["AES加密存储"] +Connection --> Masking["日志中脱敏显示"] +Masking --> Pattern1["匹配密码正则表达式"] +Masking --> Replace["替换为******"] +Encryption --> KeyManagement["密钥管理"] +KeyManagement --> Config["从配置文件读取"] +KeyManagement --> Default["使用默认密钥"] +``` + +**Diagram sources ** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L34-L39) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L247-L253) + +系统使用AES加密算法对数据源的密码等敏感信息进行加密存储,并在日志输出时对敏感信息进行脱敏处理,防止密码等敏感信息泄露。 + +**Section sources** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L34-L39) +- [DataSourceServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#L247-L253) + +## 日常维护与监控 + +### 日志管理 + +系统配置了完善的日志管理机制,通过`server-logback.xml`文件定义了多种日志输出策略: + +```mermaid +flowchart TD +LogSources["日志来源"] --> Console["控制台输出"] +LogSources --> ServerLog["服务器日志文件"] +LogSources --> JobLog["作业执行日志"] +Console --> STDOUT["STDOUT Appender"] +ServerLog --> SERVER_LOG_FILE["SERVER_LOG_FILE Appender"] +JobLog --> JOB_LOG_FILE["JOB_LOG_FILE SiftingAppender"] +SERVER_LOG_FILE --> Rolling["按大小和时间滚动"] +SERVER_LOG_FILE --> Retention["保留168个历史文件"] +JOB_LOG_FILE --> Sift["按作业执行ID分离"] +JOB_LOG_FILE --> Pattern["datavines-server.%d{yyyy-MM-dd_HH}.%i.log"] +``` + +**Diagram sources ** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L61-L77) + +日志系统实现了: +- 控制台实时输出 +- 服务器日志按小时和大小滚动 +- 作业执行日志按作业ID分离存储 +- 敏感信息自动脱敏 + +### 告警与监控 + +系统通过以下方式实现告警和监控: +- 数据库连接状态监控 +- 作业执行状态监控 +- 资源使用情况监控 +- 自定义阈值告警 + +数据库连接通过`MysqlRegistry`类管理,确保集群环境下的高可用性。 + +```mermaid +classDiagram +class MysqlRegistry { ++init(Properties properties) ++getConnection() ++acquireLock() ++releaseLock() +} +class MysqlMutex { ++acquireLock() ++releaseLock() +} +class MysqlServerStateManager { ++registerServer() ++unregisterServer() ++getOnlineServers() +} +MysqlRegistry --> MysqlMutex : "使用" +MysqlRegistry --> MysqlServerStateManager : "使用" +``` + +**Diagram sources ** +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L29-L38) + +**Section sources** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml#L21-L85) +- [MysqlRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java#L29-L38) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\350\277\236\346\216\245\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\350\277\236\346\216\245\351\205\215\347\275\256.md" new file mode 100644 index 00000000..5eff64fb --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\350\277\236\346\216\245\351\205\215\347\275\256.md" @@ -0,0 +1,401 @@ +# 数据库连接配置 + + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [ConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java) +- [JdbcUrlParser.java](file://datavines-common/src/main/java/io/datavines/common/utils/JdbcUrlParser.java) +- [DefaultDataSourceInfoUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/DefaultDataSourceInfoUtils.java) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [MysqlParameterConverter.java](file://datavines-connector/connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlParameterConverter.java) + + +## 目录 +1. [简介](#简介) +2. [核心配置文件分析](#核心配置文件分析) +3. [数据源配置详解](#数据源配置详解) +4. [连接池参数配置](#连接池参数配置) +5. [支持的数据库类型](#支持的数据库类型) +6. [多数据源配置方案](#多数据源配置方案) +7. [连接测试与故障排查](#连接测试与故障排查) + +## 简介 +DataVines是一个数据质量监控平台,其数据库连接配置主要通过Spring Boot的application.yaml文件进行管理。系统支持多种数据库类型,包括PostgreSQL、MySQL等,并使用HikariCP作为连接池实现。本文档详细说明DataVines的数据库连接配置方法,包括JDBC URL、用户名、密码、驱动类等配置项的含义,连接池参数配置,支持的数据库类型及其特定配置要求,以及主从数据库配置示例和多数据源配置方案。 + +## 核心配置文件分析 +DataVines的数据库连接配置主要位于`application.yaml`文件中,该文件定义了系统与数据库的连接信息和连接池参数。 + +```mermaid +flowchart TD +A[application.yaml] --> B[spring.datasource] +A --> C[spring.quartz] +B --> D[JDBC连接信息] +B --> E[HikariCP连接池配置] +C --> F[Quartz调度器配置] +``` + +**图表来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +**本节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 数据源配置详解 +DataVines的数据源配置包含JDBC连接所需的所有基本信息,这些配置项在`application.yaml`文件中定义。 + +### JDBC连接配置项 +DataVines的JDBC连接配置包含以下关键参数: + +| 配置项 | 说明 | 示例值 | +|--------|------|--------| +| driver-class-name | JDBC驱动类名 | org.postgresql.Driver | +| url | JDBC连接URL | jdbc:postgresql://127.0.0.1:5432/datavines | +| username | 数据库用户名 | postgres | +| password | 数据库密码 | 123456 | + +这些配置项通过`BaseJdbcDataSourceInfo`类进行抽象和管理,该类定义了所有JDBC数据源的通用属性和方法。 + +```mermaid +classDiagram +class BaseJdbcDataSourceInfo { ++String getUser() ++String getPassword() ++String getHost() ++String getPort() ++String getDatabase() ++String getSchema() ++String getProperties() ++String getDriverClass() ++String getType() ++String getJdbcUrl() ++String getUniqueKey() +} +class PostgreSqlDataSourceInfo { ++String getAddress() ++String getDriverClass() ++String getType() ++String getValidationQuery() +} +class MysqlDataSourceInfo { ++String getAddress() ++String getDriverClass() ++String getType() ++String getValidationQuery() +} +BaseJdbcDataSourceInfo <|-- PostgreSqlDataSourceInfo +BaseJdbcDataSourceInfo <|-- MysqlDataSourceInfo +``` + +**图表来源** +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) + +**本节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +### JDBC URL结构 +JDBC URL遵循标准格式:`jdbc:数据库类型://主机:端口/数据库名?参数`。DataVines使用`JdbcUrlParser`类解析JDBC URL,提取连接信息。 + +```mermaid +flowchart TD +A[JDBC URL] --> B{解析URL} +B --> C[提取数据库类型] +B --> D[提取主机地址] +B --> E[提取端口号] +B --> F[提取数据库名] +B --> G[提取连接参数] +C --> H[ConnectionInfo.type] +D --> H[ConnectionInfo.host] +E --> H[ConnectionInfo.port] +F --> H[ConnectionInfo.database] +G --> H[ConnectionInfo.properties] +H[ConnectionInfo] --> I[返回连接信息] +``` + +**图表来源** +- [JdbcUrlParser.java](file://datavines-common/src/main/java/io/datavines/common/utils/JdbcUrlParser.java) + +**本节来源** +- [JdbcUrlParser.java](file://datavines-common/src/main/java/io/datavines/common/utils/JdbcUrlParser.java) + +## 连接池参数配置 +DataVines使用HikariCP作为连接池实现,连接池参数在`application.yaml`文件中通过`spring.datasource.hikari`配置项进行设置。 + +### HikariCP连接池参数 +| 参数 | 说明 | 示例值 | +|------|------|--------| +| connection-test-query | 连接测试查询语句 | select 1 | +| minimum-idle | 最小空闲连接数 | 5 | +| maximum-pool-size | 最大连接池大小 | 50 | +| connection-timeout | 连接超时时间(毫秒) | 30000 | +| idle-timeout | 空闲超时时间(毫秒) | 600000 | +| validation-timeout | 验证超时时间(毫秒) | 3000 | +| leak-detection-threshold | 连接泄漏检测阈值 | 0 | +| initialization-fail-timeout | 初始化失败超时时间 | 1 | + +### 连接池配置示例 +```yaml +spring: + datasource: + hikari: + connection-test-query: select 1 + minimum-idle: 5 + auto-commit: true + validation-timeout: 3000 + pool-name: datavines + maximum-pool-size: 50 + connection-timeout: 30000 + idle-timeout: 600000 + leak-detection-threshold: 0 + initialization-fail-timeout: 1 +``` + +连接池的管理由`JdbcDataSourceManager`类负责,该类使用单例模式管理所有数据源连接。 + +```mermaid +classDiagram +class JdbcDataSourceManager { +-ConcurrentHashMap dataSourceMap +-static Singleton INSTANCE ++static getInstance() ++getDataSource(BaseJdbcDataSourceInfo) ++getDataSource(Map) ++getDataSource(Properties) ++close() +} +class HikariConfig { ++setJdbcUrl(String) ++setUsername(String) ++setPassword(String) ++setDriverClassName(String) ++setMaximumPoolSize(int) +} +class HikariDataSource { ++getConnection() ++close() +} +JdbcDataSourceManager --> HikariConfig +HikariConfig --> HikariDataSource +``` + +**图表来源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +**本节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +## 支持的数据库类型 +DataVines支持多种数据库类型,每种数据库类型都有其特定的配置要求。 + +### PostgreSQL配置 +PostgreSQL是DataVines的默认数据库,配置示例如下: + +```yaml +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://127.0.0.1:5432/datavines + username: postgres + password: 123456 +``` + +PostgreSQL特定的配置在`PostgreSqlDataSourceInfo`类中定义: + +```java +public class PostgreSqlDataSourceInfo extends BaseJdbcDataSourceInfo { + @Override + public String getAddress() { + return "jdbc:postgresql://"+getHost()+":"+getPort(); + } + + @Override + public String getDriverClass() { + return "org.postgresql.Driver"; + } + + @Override + public String getType() { + return "postgresql"; + } + + @Override + public String getValidationQuery() { + return "SELECT 'x'"; + } +} +``` + +### MySQL配置 +MySQL配置需要激活mysql profile,并使用相应的驱动和URL格式: + +```yaml +--- +spring: + config: + activate: + on-profile: mysql + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/datavines?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: 123456 + quartz: + properties: + org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate +``` + +MySQL的参数转换在`MysqlParameterConverter`类中实现: + +```java +public class MysqlParameterConverter extends JdbcParameterConverter { + @Override + protected String getUrl(Map parameter) { + String url = String.format("jdbc:mysql://%s:%s/%s", + parameter.get(HOST), + parameter.get(PORT), + parameter.get(DATABASE)); + String properties = (String)parameter.get(PROPERTIES); + if (StringUtils.isNotEmpty(properties)) { + url += "?" + properties; + } + return url; + } +} +``` + +### 其他支持的数据库 +DataVines还支持以下数据库类型: +- ClickHouse +- Databend +- DM (达梦) +- Doris +- Hive +- Impala +- MongoDB +- Oracle +- Presto +- SQL Server +- StarRocks +- Trino + +每种数据库类型都有对应的连接器插件,位于`datavines-connector-plugins`目录下。 + +**本节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [MysqlParameterConverter.java](file://datavines-connector/connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlParameterConverter.java) + +## 多数据源配置方案 +DataVines支持多数据源配置,允许系统同时连接多个不同的数据库。 + +### 主从数据库配置 +主从数据库配置可以通过定义多个数据源来实现。系统使用`ConnectionInfo`类来存储连接信息: + +```java +@Data +public class ConnectionInfo { + private String type; + private String url; + private String host; + private String port; + private String driverName; + private String catalog; + private String database; + private String schema; + private String properties; + private String address; + private String user; + private String password; + private Map allConfigMap = new HashMap<>(); +} +``` + +### 多数据源管理 +多数据源的管理通过`JdbcDataSourceManager`的`dataSourceMap`实现,使用连接信息的MD5哈希值作为唯一键: + +```java +private String getUniqueKey(Map configMap) { + String url = String.valueOf(configMap.get(URL)); + String username = String.valueOf(configMap.get(USER)); + String password = String.valueOf(configMap.get(PASSWORD)); + return Md5Utils.getMd5(String.format("%s@@%s@@%s",url,username,password),false); +} +``` + +当需要获取数据源时,系统首先检查`dataSourceMap`中是否已存在对应的连接池,如果不存在则创建新的连接池并缓存。 + +```mermaid +sequenceDiagram +participant Application as 应用程序 +participant Manager as JdbcDataSourceManager +participant Map as dataSourceMap +participant Hikari as HikariDataSource +Application->>Manager : getDataSource(configMap) +Manager->>Map : get(uniqueKey) +alt 连接池已存在 +Map-->>Manager : 返回现有连接池 +Manager-->>Application : 返回数据源 +else 连接池不存在 +Manager->>Manager : 创建HikariConfig +Manager->>Manager : 设置连接参数 +Manager->>Hikari : 创建HikariDataSource +Manager->>Map : put(uniqueKey, dataSource) +Manager-->>Application : 返回新创建的数据源 +end +``` + +**图表来源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +**本节来源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [ConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java) + +## 连接测试与故障排查 +DataVines提供了连接测试和故障排查机制,确保数据库连接的可靠性。 + +### 连接测试流程 +系统通过`DefaultDataSourceInfoUtils`类获取默认数据源的连接信息: + +```java +public static ConnectionInfo getDefaultConnectionInfo(){ + javax.sql.DataSource defaultDataSource = + SpringApplicationContext.getBean(javax.sql.DataSource.class); + HikariDataSource hikariDataSource = (HikariDataSource)defaultDataSource; + + ConnectionInfo connectionInfo = JdbcUrlParser.getConnectionInfo(hikariDataSource.getJdbcUrl(), + hikariDataSource.getUsername(),hikariDataSource.getPassword()); + + if (connectionInfo != null) { + connectionInfo.setDriverName(hikariDataSource.getDriverClassName()); + } + + return connectionInfo; +} +``` + +### 故障排查指南 +当数据库连接出现问题时,可以按照以下步骤进行排查: + +1. **检查配置文件**:确认`application.yaml`中的数据库连接参数是否正确 +2. **检查网络连接**:确保应用程序服务器能够访问数据库服务器 +3. **检查数据库状态**:确认数据库服务正在运行 +4. **检查连接池状态**:查看连接池是否已满或存在连接泄漏 +5. **查看日志信息**:检查应用程序日志中的错误信息 + +### 常见问题及解决方案 +| 问题现象 | 可能原因 | 解决方案 | +|---------|---------|---------| +| 连接超时 | 网络问题或数据库负载过高 | 检查网络连接,增加connection-timeout值 | +| 认证失败 | 用户名或密码错误 | 检查用户名和密码配置 | +| 驱动类找不到 | JDBC驱动未正确加载 | 确认驱动类名正确且JAR包在类路径中 | +| 连接池耗尽 | 最大连接数设置过小 | 增加maximum-pool-size值 | +| SSL连接问题 | SSL配置不正确 | 在URL中添加useSSL=false参数 | + +**本节来源** +- [DefaultDataSourceInfoUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/DefaultDataSourceInfoUtils.java) +- [JdbcUrlParser.java](file://datavines-common/src/main/java/io/datavines/common/utils/JdbcUrlParser.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256.md" new file mode 100644 index 00000000..364ebf6d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256.md" @@ -0,0 +1,255 @@ +# 数据库配置 + + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcUrlParser.java](file://datavines-common/src/main/java/io/datavines/common/utils/JdbcUrlParser.java) +- [DefaultDataSourceInfoUtils.java](file://datavines-server/src/main/java/io/datavines/server/utils/DefaultDataSourceInfoUtils.java) + + +## 目录 +1. [简介](#简介) +2. [数据源配置](#数据源配置) +3. [连接池参数配置](#连接池参数配置) +4. [数据库类型支持](#数据库类型支持) +5. [初始化脚本执行](#初始化脚本执行) +6. [主从数据库配置](#主从数据库配置) +7. [连接超时与最大连接数](#连接超时与最大连接数) +8. [数据库性能调优建议](#数据库性能调优建议) +9. [数据库迁移策略和版本管理](#数据库迁移策略和版本管理) +10. [数据库备份与恢复](#数据库备份与恢复) + +## 简介 +DataVines 是一个数据质量监控平台,其核心功能依赖于稳定可靠的数据库连接。本文档详细说明了 DataVines 的数据库配置,包括数据源配置、连接池参数、支持的数据库类型、初始化脚本执行、主从数据库配置、连接超时、最大连接数等关键参数。同时,本文档还提供了数据库性能调优建议、迁移策略、版本管理方法以及备份和恢复方案。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 数据源配置 +DataVines 使用 Spring Boot 框架进行配置管理,其数据源配置主要在 `application.yaml` 文件中定义。该文件位于 `datavines-server/src/main/resources/` 目录下。 + +配置文件中通过 `spring.datasource` 前缀定义了数据库连接的核心参数,包括驱动类名、URL、用户名和密码。DataVines 支持多种数据库,通过配置文件中的 profile 机制可以轻松切换不同的数据库。 + +```yaml +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://127.0.0.1:5432/datavines + username: postgres + password: 123456 +``` + +对于 MySQL 数据库,可以通过激活 `mysql` profile 来使用相应的配置: + +```yaml +--- +spring: + config: + activate: + on-profile: mysql + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/datavines?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: 123456 +``` + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 连接池参数配置 +DataVines 使用 HikariCP 作为其数据库连接池实现,这是目前性能最好的连接池之一。连接池的配置在 `application.yaml` 文件的 `spring.datasource.hikari` 部分进行定义。 + +以下是关键的连接池参数及其说明: + +- **connection-test-query**: 连接测试查询语句,用于验证连接的有效性。默认值为 `select 1`。 +- **minimum-idle**: 连接池中保持的最小空闲连接数。默认值为 5。 +- **auto-commit**: 是否自动提交事务。默认值为 `true`。 +- **validation-timeout**: 连接验证超时时间(毫秒)。默认值为 3000。 +- **pool-name**: 连接池的名称。默认值为 `datavines`。 +- **maximum-pool-size**: 连接池中允许的最大连接数。默认值为 50。 +- **connection-timeout**: 从连接池获取连接的超时时间(毫秒)。默认值为 30000。 +- **idle-timeout**: 连接在池中闲置的超时时间(毫秒)。默认值为 600000。 +- **leak-detection-threshold**: 连接泄漏检测阈值(毫秒)。如果连接在指定时间内未关闭,则会记录警告。默认值为 0(禁用)。 +- **initialization-fail-timeout**: 初始化失败超时时间(毫秒)。如果连接池初始化失败,等待的时间。默认值为 1。 + +```yaml +spring: + datasource: + hikari: + connection-test-query: select 1 + minimum-idle: 5 + auto-commit: true + validation-timeout: 3000 + pool-name: datavines + maximum-pool-size: 50 + connection-timeout: 30000 + idle-timeout: 600000 + leak-detection-threshold: 0 + initialization-fail-timeout: 1 +``` + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 数据库类型支持 +DataVines 通过插件化架构支持多种数据库类型。核心的 JDBC 连接管理由 `JdbcDataSourceManager` 类实现,该类位于 `datavines-common` 模块中。 + +`JdbcDataSourceManager` 是一个单例类,负责管理所有数据库连接。它使用 `ConcurrentHashMap` 来缓存数据源,确保线程安全。当需要获取数据源时,会根据配置参数生成一个唯一的 key,然后从缓存中查找或创建新的数据源。 + +```java +public class JdbcDataSourceManager { + private final ConcurrentHashMap dataSourceMap = new ConcurrentHashMap<>(); + + public static JdbcDataSourceManager getInstance() { + return Singleton.INSTANCE; + } + + public DataSource getDataSource(BaseJdbcDataSourceInfo baseJdbcDataSourceInfo) throws SQLException { + // ... 实现细节 + } +} +``` + +`BaseJdbcDataSourceInfo` 是一个抽象基类,定义了所有 JDBC 数据源的基本信息和方法。具体的数据库类型(如 MySQL、PostgreSQL)通过继承此类并实现特定的方法来支持。 + +```java +public abstract class BaseJdbcDataSourceInfo { + protected final Map param; + + public BaseJdbcDataSourceInfo(Map param) { + this.param = param; + } + + public abstract String getDriverClass(); + public abstract String getType(); + public abstract String getAddress(); +} +``` + +**Section sources** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java#L32-L43) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java#L34-L42) + +## 初始化脚本执行 +DataVines 提供了数据库初始化脚本,用于创建所需的表结构和初始数据。脚本文件位于 `scripts/sql/` 目录下,主要文件为 `datavines-mysql.sql`。 + +该 SQL 脚本包含了创建所有必要表的语句,包括 Quartz 调度框架所需的表和 DataVines 自身的业务表。例如: + +```sql +DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`; +CREATE TABLE `QRTZ_BLOB_TRIGGERS` ( + `SCHED_NAME` varchar(120) NOT NULL, + `TRIGGER_NAME` varchar(200) NOT NULL, + `TRIGGER_GROUP` varchar(200) NOT NULL, + `BLOB_DATA` blob, + PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`), + KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`), + CONSTRAINT `QRTZ_BLOB_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +``` + +除了 Quartz 表,脚本还创建了 DataVines 的业务表,如 `dv_datasource`(数据源表)、`dv_job`(作业表)、`dv_job_execution`(作业执行实例表)等。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql#L1-L12) + +## 主从数据库配置 +DataVines 当前的配置主要针对单个主数据库。通过 `application.yaml` 文件中的 `spring.datasource` 配置,可以指定主数据库的连接信息。 + +对于读写分离的主从架构,DataVines 目前没有内置的配置支持。但可以通过以下方式实现: + +1. 在数据库层面配置主从复制。 +2. 在应用层面,通过自定义数据源路由,将读操作路由到从库,写操作路由到主库。 + +虽然当前代码中没有直接体现主从配置,但 `JdbcDataSourceManager` 的设计允许通过扩展来支持多数据源。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 连接超时与最大连接数 +连接超时和最大连接数是数据库连接池的重要参数,直接影响系统的稳定性和性能。 + +在 `application.yaml` 文件中,`connection-timeout` 参数定义了从连接池获取连接的超时时间,单位为毫秒。如果在指定时间内无法获取到连接,将抛出异常。建议根据应用的响应时间要求和数据库的负载情况来设置此值。 + +`maximum-pool-size` 参数定义了连接池中允许的最大连接数。这个值需要根据数据库服务器的处理能力和应用的并发需求来合理设置。过小的值可能导致连接争用,过大的值可能耗尽数据库资源。 + +```yaml +spring: + datasource: + hikari: + connection-timeout: 30000 + maximum-pool-size: 50 +``` + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L35-L36) + +## 数据库性能调优建议 +为了确保 DataVines 的高效运行,以下是一些数据库性能调优建议: + +### 索引优化 +- 为频繁查询的字段创建索引,如 `dv_job_execution` 表的 `job_id` 和 `status` 字段。 +- 避免在索引字段上使用函数或表达式,这会导致索引失效。 +- 定期分析和优化索引,删除不必要的索引以减少写操作的开销。 + +### 查询优化 +- 使用 `EXPLAIN` 分析查询计划,确保查询使用了正确的索引。 +- 避免使用 `SELECT *`,只选择需要的字段。 +- 合理使用分页,避免一次性查询大量数据。 +- 对于复杂的查询,考虑使用视图或物化视图。 + +### 连接池调优 +- 根据应用的并发量调整 `maximum-pool-size`。 +- 设置合理的 `idle-timeout` 和 `connection-timeout`,避免连接泄漏和长时间等待。 +- 监控连接池的使用情况,及时发现和解决连接问题。 + +**Section sources** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 数据库迁移策略和版本管理 +DataVines 的数据库迁移策略主要依赖于手动执行 SQL 脚本。`scripts/sql/datavines-mysql.sql` 文件包含了完整的数据库结构。 + +对于版本管理,建议采用以下策略: + +1. 每次发布新版本时,提供一个增量的 SQL 脚本,只包含新增或修改的表结构和数据。 +2. 使用版本控制工具(如 Git)管理这些 SQL 脚本。 +3. 在执行迁移脚本前,先备份数据库。 +4. 记录每次迁移的版本号和执行时间。 + +虽然当前代码中没有使用 Liquibase 或 Flyway 等自动化迁移工具,但可以通过引入这些工具来实现更可靠的数据库版本管理。 + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) + +## 数据库备份与恢复 +数据库的备份与恢复是保障数据安全的关键措施。 + +### 备份策略 +- **全量备份**:定期(如每天)对整个数据库进行全量备份。 +- **增量备份**:在全量备份的基础上,每天备份自上次备份以来的变化。 +- **备份存储**:将备份文件存储在安全的位置,最好与生产环境物理隔离。 + +### 恢复流程 +1. 停止 DataVines 服务。 +2. 恢复数据库备份文件。 +3. 启动数据库服务。 +4. 启动 DataVines 服务。 +5. 验证数据的完整性和服务的正常运行。 + +可以使用 MySQL 自带的 `mysqldump` 工具进行备份和恢复: + +```bash +# 备份 +mysqldump -u root -p datavines > datavines_backup.sql + +# 恢复 +mysql -u root -p datavines < datavines_backup.sql +``` + +**Section sources** +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\345\237\272\347\241\200\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\345\237\272\347\241\200\351\205\215\347\275\256.md" new file mode 100644 index 00000000..419b738a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\345\237\272\347\241\200\351\205\215\347\275\256.md" @@ -0,0 +1,449 @@ +# 基础配置 + + +**本文档中引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [.env](file://deploy/compose/.env) + + +## 目录 +1. [简介](#简介) +2. [核心配置项详解](#核心配置项详解) +3. [环境特定配置](#环境特定配置) +4. [配置文件加载机制](#配置文件加载机制) +5. [日志配置](#日志配置) +6. [配置最佳实践](#配置最佳实践) + +## 简介 + +DataVines服务器的基础配置主要通过`application.yaml`文件进行管理。该配置文件位于`datavines-server/src/main/resources/`目录下,是Spring Boot应用的核心配置文件。本文档详细说明了其中的关键配置项,包括服务器端口、应用名称、上下文路径等基本设置,以及如何根据不同的部署环境(开发、测试、生产)调整这些配置。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## 核心配置项详解 + +### server.port(服务器端口) + +**作用**:定义DataVines服务器监听的端口号。 + +**可选值**:1024-65535之间的任意有效端口号(避免使用系统保留端口)。 + +**默认值**:5600 + +**配置示例**: +```yaml +server: + port: 5600 +``` + +在`DataVinesServer.java`的`initCommonProperties`方法中,该配置值会被读取并存储到`CommonPropertyUtils`中,供其他组件使用: +```java +CommonPropertyUtils.setValue("server.port", environment.getProperty("server.port")); +``` + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L69-L71) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L149) + +### spring.application.name(应用名称) + +**作用**:定义Spring Boot应用的名称,用于服务发现、监控和日志标识。 + +**可选值**:任意字符串,建议使用小写字母和连字符。 + +**默认值**:datavines-server + +**配置示例**: +```yaml +spring: + application: + name: datavines-server +``` + +该名称在多个地方被使用: +1. 作为应用实例的标识 +2. 在监控系统中作为应用标签 +3. 在日志配置中作为应用标识 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L21-L22) + +### server.servlet.context-path(上下文路径) + +**作用**:定义应用的上下文路径,即应用的访问前缀。 + +**可选值**:以斜杠开头的字符串路径,如`/datavines`、`/api`等。 + +**默认值**:空(即应用直接挂载在根路径下) + +**配置示例**: +```yaml +server: + servlet: + context-path: /datavines +``` + +虽然在当前的`application.yaml`文件中没有显式配置此选项,但它是Spring Boot支持的重要配置项,可用于将应用部署在特定的URL路径下。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +### spring.mvc.pathmatch.matching-strategy + +**作用**:配置Spring MVC的路径匹配策略。 + +**可选值**: +- `ant_path_matcher`:使用传统的Ant风格路径匹配器 +- `path_pattern_parser`:使用新的PathPatternParser(Spring 5.3+推荐) + +**默认值**:根据Spring版本而定 + +**配置示例**: +```yaml +spring: + mvc: + pathmatch: + matching-strategy: ant_path_matcher +``` + +此配置确保了URL路径匹配的行为一致性,特别是在处理通配符和路径变量时。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L60-L62) + +### management.endpoints.web.exposure.include + +**作用**:控制Spring Boot Actuator端点的暴露范围。 + +**可选值**: +- `*`:暴露所有端点 +- `health,info`:仅暴露指定的端点 +- 具体端点名称列表 + +**默认值**:根据安全策略而定 + +**配置示例**: +```yaml +management: + endpoints: + web: + exposure: + include: '*' +``` + +此配置允许通过HTTP访问所有Actuator端点,用于监控和管理应用,但在生产环境中应谨慎使用,建议只暴露必要的端点。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L72-L76) + +## 环境特定配置 + +DataVines支持通过Spring Profiles实现环境特定的配置。在`application.yaml`文件中,使用`---`分隔符定义了不同的配置环境。 + +### MySQL环境配置 + +当激活`mysql` profile时,应用会使用MySQL作为数据源: + +```yaml +--- +spring: + config: + activate: + on-profile: mysql + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/datavines?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: 123456 + quartz: + properties: + org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate +``` + +### PostgreSQL环境配置 + +默认配置使用PostgreSQL作为数据源: + +```yaml +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://127.0.0.1:5432/datavines + username: postgres + password: 123456 +``` + +### 激活特定环境 + +可以通过以下方式激活特定环境: + +1. **命令行参数**: + ```bash + java -jar datavines-server.jar --spring.profiles.active=mysql + ``` + +2. **环境变量**(在Docker部署中): + ```env + SPRING_PROFILES_ACTIVE=mysql + ``` + +3. **JVM系统属性**: + ```bash + java -Dspring.profiles.active=mysql -jar datavines-server.jar + ``` + +在`deploy/compose/.env`文件中,通过环境变量设置了MySQL配置: +```env +SPRING_PROFILES_ACTIVE=mysql +SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/datavines?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8 +SPRING_DATASOURCE_USERNAME=root +SPRING_DATASOURCE_PASSWORD=123456 +SPRING_DATASOURCE_DRIVER-CLASS_NAME=com.mysql.cj.jdbc.Driver +``` + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml#L83-L95) +- [.env](file://deploy/compose/.env) + +## 配置文件加载机制 + +DataVines遵循Spring Boot的标准配置加载顺序和优先级机制。配置的加载优先级从高到低如下: + +### 配置加载优先级 + +1. **命令行参数**:`--property=value`形式的参数 +2. **来自SPRING_APPLICATION_JSON的属性**:环境变量中内联的JSON +3. **ServletConfig初始化参数** +4. **ServletContext初始化参数** +5. **JNDI属性**:来自`java:comp/env`的属性 +6. **Java系统属性**:`System.getProperties()` +7. **操作系统环境变量** +8. **随机值属性**:`random.*`属性 +9. **jar包外的profile-specific配置文件**:如`application-{profile}.yaml` +10. **jar包内的profile-specific配置文件**:如`application-{profile}.yaml` +11. **jar包外的application配置文件**:如`application.yaml` +12. **jar包内的application配置文件**:如`application.yaml` +13. **@Configuration类上的@PropertySource注解** +14. **默认属性**:通过`SpringApplication.setDefaultProperties`设置 + +### 配置源实现 + +在代码层面,DataVines使用了多种配置管理机制: + +1. **CommonPropertyUtils**:提供统一的配置访问接口,支持从不同来源获取配置值。 + +2. **Spring Environment**:通过`@Autowired`注入`Environment`对象,获取配置属性。 + +3. **Profile激活**:通过`spring.config.activate.on-profile`指定配置块的激活条件。 + +在`DataVinesServer.java`中,配置初始化过程如下: +```java +private void initCommonProperties(){ + javax.sql.DataSource defaultDataSource = + SpringApplicationContext.getBean(javax.sql.DataSource.class); + HikariDataSource hikariDataSource = (HikariDataSource)defaultDataSource; + CommonPropertyUtils.setValue("driver",hikariDataSource.getDriverClassName()); + CommonPropertyUtils.setValue("url",hikariDataSource.getJdbcUrl()); + CommonPropertyUtils.setValue("username", hikariDataSource.getUsername()); + CommonPropertyUtils.setValue("password", hikariDataSource.getPassword()); + CommonPropertyUtils.setValue("server.port", environment.getProperty("server.port")); + + String registryType = CommonPropertyUtils + .getString(CommonPropertyUtils.REGISTRY_TYPE, CommonPropertyUtils.REGISTRY_TYPE_DEFAULT); + if ("default".equals(registryType)) { + CommonPropertyUtils.setValue(CommonPropertyUtils.REGISTRY_TYPE, + hikariDataSource.getJdbcUrl().contains("mysql") ? "mysql" : "postgresql"); + } +} +``` + +此方法在应用启动时被调用,将Spring配置中的数据源信息同步到`CommonPropertyUtils`中,供其他组件使用。 + +**Section sources** +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L141-L157) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) + +## 日志配置 + +DataVines的日志配置通过`server-logback.xml`文件进行管理,该文件位于`datavines-server/src/main/resources/`目录下。 + +### 日志配置特点 + +1. **多appender配置**:支持控制台输出、作业日志文件和服务器日志文件。 + +2. **作业日志分离**:使用`SiftingAppender`为每个作业执行创建独立的日志文件。 + +3. **滚动策略**:服务器日志采用基于时间和大小的滚动策略。 + +```xml + + + + + + + + [%level] %date{yyyy-MM-dd HH:mm:ss.SSS} %logger{96}:[%line] - %msg%n + + UTF-8 + + + + + + + jobExecutionUniqueId + ${log.base} + + + + ${log.base}/${jobExecutionUniqueId}.log + + + [%level] %date{yyyy-MM-dd HH:mm:ss.SSS} %logger{96}:[%line] - %message%n + + UTF-8 + + true + + + + + + + ${log.base}/datavines-server.log + + ${log.base}/datavines-server.%d{yyyy-MM-dd_HH}.%i.log + 168 + 200MB + + + + [%level] %date{yyyy-MM-dd HH:mm:ss.SSS} %logger{96}:[%line] - %msg%n + + UTF-8 + + + + + + + + + +``` + +### 日志配置说明 + +- **扫描机制**:`scan="true"`和`scanPeriod="120 seconds"`允许在运行时动态更新日志配置。 +- **字符编码**:明确指定UTF-8编码,避免中文日志乱码。 +- **日志级别**:根日志级别设置为INFO,可根据需要调整。 +- **日志路径**:通过`log.base`属性定义日志基础路径。 + +**Section sources** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +## 配置最佳实践 + +### 开发环境配置 + +在开发环境中,建议使用以下配置: + +```yaml +spring: + profiles: dev + datasource: + url: jdbc:postgresql://localhost:5432/datavines_dev + username: dev_user + password: dev_password + jpa: + show-sql: true + hibernate: + ddl-auto: update + +server: + port: 5600 + servlet: + context-path: /datavines + +logging: + level: + io.datavines: DEBUG +``` + +### 测试环境配置 + +在测试环境中,建议使用独立的数据库和更严格的日志级别: + +```yaml +spring: + profiles: test + datasource: + url: jdbc:postgresql://test-db:5432/datavines_test + username: test_user + password: test_password + jpa: + show-sql: false + hibernate: + ddl-auto: validate + +management: + endpoints: + web: + exposure: + include: health,info +``` + +### 生产环境配置 + +在生产环境中,建议使用以下安全配置: + +```yaml +spring: + profiles: prod + datasource: + url: jdbc:postgresql://prod-db:5432/datavines_prod + username: prod_user + password: ${DB_PASSWORD} # 从环境变量读取 + quartz: + job-store-type: jdbc + properties: + org.quartz.threadPool.threadCount: 50 + +server: + port: 8080 + servlet: + context-path: /datavines + tomcat: + max-threads: 200 + min-spare-threads: 10 + +management: + endpoints: + web: + exposure: + include: health,info + health: + db: + enabled: false # 禁用数据库健康检查以提高安全性 +``` + +### 配置管理建议 + +1. **敏感信息保护**:数据库密码等敏感信息不应硬编码在配置文件中,应通过环境变量或密钥管理服务提供。 + +2. **配置外化**:将环境特定的配置外化到`application-{profile}.yaml`文件中,便于不同环境的部署。 + +3. **配置验证**:在应用启动时验证关键配置项的有效性。 + +4. **配置文档化**:为每个配置项提供清晰的文档说明,包括作用、可选值和默认值。 + +5. **配置版本控制**:将配置文件纳入版本控制系统,跟踪配置变更历史。 + +**Section sources** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\345\256\211\345\205\250\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\345\256\211\345\205\250\351\205\215\347\275\256.md" new file mode 100644 index 00000000..f8efcc86 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\345\256\211\345\205\250\351\205\215\347\275\256.md" @@ -0,0 +1,360 @@ +# 安全配置 + + +**本文档引用的文件** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java) +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java) +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) +- [HttpUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/HttpUtils.java) + + +## 目录 +1. [简介](#简介) +2. [JWT认证配置](#jwt认证配置) +3. [验证码配置](#验证码配置) +4. [接口权限控制](#接口权限控制) +5. [安全策略配置](#安全策略配置) +6. [生产环境安全加固建议](#生产环境安全加固建议) +7. [总结](#总结) + +## 简介 + +DataVines服务器的安全配置体系旨在保护API接口免受未授权访问,确保系统的数据安全和用户隐私。本系统采用JWT(JSON Web Token)认证机制进行用户身份验证,结合验证码机制增强登录安全性,并通过注解方式实现细粒度的接口权限控制。安全配置主要分布在`datavines-server`和`datavines-core`模块中,通过Spring框架的拦截器和AOP技术实现。 + +系统的核心安全组件包括: +- **JWT认证**:使用`io.jsonwebtoken`库生成和验证JWT令牌,通过`TokenManager`类集中管理令牌的生成、解析和验证逻辑。 +- **验证码**:集成`kaptcha`库生成图形验证码,验证码信息通过JWT令牌进行安全传输,防止中间人攻击。 +- **权限控制**:通过`@AuthIgnore`和`@CheckTokenExist`注解标记接口,由`AuthenticationInterceptor`拦截器在请求处理前进行权限校验。 + +**Section sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L1-L100) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L1-L50) +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java#L1-L28) + +## JWT认证配置 + +DataVines服务器使用JWT(JSON Web Token)作为主要的认证机制,通过在客户端和服务器之间传递加密的令牌来验证用户身份。JWT配置主要在`TokenManager`类中实现,该类负责令牌的生成、解析和验证。 + +### JWT配置参数 + +JWT的配置参数通过Spring的`@Value`注解从配置文件中注入,支持在`application.yaml`中进行自定义: + +```java +@Value("${jwt.token.secret:asdqwe}") +private String tokenSecret; + +@Value("${jwt.token.timeout:8640000}") +private Long timeout; + +@Value("${jwt.token.algorithm:HS256}") +private String algorithm; +``` + +| 配置项 | 默认值 | 说明 | +| :--- | :--- | :--- | +| `jwt.token.secret` | asdqwe | JWT签名密钥,用于生成和验证令牌的HMAC签名,建议在生产环境中使用强随机字符串 | +| `jwt.token.timeout` | 8640000 | 令牌有效期(毫秒),默认为2.4小时(8640000毫秒),可根据安全需求调整 | +| `jwt.token.algorithm` | HS256 | JWT签名算法,支持HS256、HS384、HS512等HMAC算法 | + +### JWT令牌结构 + +JWT令牌由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。DataVines在载荷中存储了用户的关键信息: + +- `un` (TOKEN_USER_NAME): 用户名 +- `up` (TOKEN_USER_PASSWORD): 用户密码(已加密) +- `ct` (TOKEN_CREATE_TIME): 令牌创建时间戳 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Server as 服务器 +participant TokenManager as TokenManager +Client->>Server : 发送用户名和密码 +Server->>TokenManager : 调用generateToken() +TokenManager->>TokenManager : 创建Claims包含用户名、密码、创建时间 +TokenManager->>TokenManager : 使用HS256算法和密钥生成JWT +TokenManager-->>Server : 返回JWT令牌 +Server-->>Client : 返回包含令牌的响应 +Client->>Server : 后续请求携带Authorization头 +Server->>TokenManager : 调用validateToken()验证令牌 +TokenManager-->>Server : 返回验证结果 +Server-->>Client : 处理请求或返回401错误 +``` + +**Diagram sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L42-L62) +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L89-L98) + +**Section sources** +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java#L40-L100) + +## 验证码配置 + +为了防止暴力破解和自动化攻击,DataVines服务器在登录流程中集成了图形验证码机制。验证码配置通过`KaptchaConfig`类实现,该类使用`kaptcha`库生成可配置的验证码图片。 + +### 验证码配置参数 + +验证码的外观和行为可以通过`application.yaml`中的属性进行配置,所有配置项都使用`@Value`注解注入到`KaptchaConfig`类中: + +```java +@Value("${kaptcha.border:yes}") +private String kaptchaBorder; + +@Value("${kaptcha.border.color:105,179,90}") +private String kaptchaBorderColor; + +@Value("${kaptcha.textproducer.font.color:blue}") +private String kaptchaTextproducerFontColor; + +@Value("${kaptcha.image.width:125}") +private String kaptchaImageWidth; + +@Value("${kaptcha.image.height:65}") +private String kaptchaImageHeight; + +@Value("${kaptcha.textproducer.font.size:45}") +private String kaptchaTextproducerFontSize; + +@Value("${kaptcha.session.key:code}") +private String kaptchaSessionKey; + +@Value("${kaptcha.textproducer.char.length:4}") +private String getKaptchaTextproducerCharLength; + +@Value("${kaptcha.textproducer.font.names:cmr10}") +private String kaptchaTextproducerFontNames; +``` + +| 配置项 | 默认值 | 说明 | +| :--- | :--- | :--- | +| `kaptcha.border` | yes | 是否显示边框 | +| `kaptcha.border.color` | 105,179,90 | 边框颜色(RGB格式) | +| `kaptcha.textproducer.font.color` | blue | 验证码字体颜色 | +| `kaptcha.image.width` | 125 | 图片宽度(像素) | +| `kaptcha.image.height` | 65 | 图片高度(像素) | +| `kaptcha.textproducer.font.size` | 45 | 字体大小 | +| `kaptcha.session.key` | code | 验证码在会话中的键名 | +| `kaptcha.textproducer.char.length` | 4 | 验证码字符长度 | +| `kaptcha.textproducer.font.names` | cmr10 | 字体名称 | + +### 验证码安全机制 + +与传统的将验证码存储在服务器会话中的方式不同,DataVines采用了更安全的JWT-based验证码机制。验证码的值被加密存储在JWT令牌中,而不是服务器内存中,这使得系统更容易扩展和集群化。 + +`VerificationUtil`类负责验证码的生成和验证: + +1. **生成验证码**:调用`createVerificationCodeAndImage()`方法,生成随机验证码文本,并将其与过期时间一起编码到JWT令牌中。 +2. **验证验证码**:调用`validVerificationCode()`方法,解析JWT令牌,检查验证码是否过期(默认5分钟)以及用户输入的验证码是否匹配。 + +```mermaid +flowchart TD +A[客户端请求验证码] --> B[服务器生成随机验证码] +B --> C[将验证码和创建时间放入JWT Claims] +C --> D[使用TokenManager生成JWT令牌] +D --> E[生成验证码图片] +E --> F[Base64编码图片] +F --> G[返回Base64图片和JWT令牌] +G --> H[客户端显示图片并提交表单] +H --> I[服务器解析JWT令牌] +I --> J{令牌是否过期?} +J --> |是| K[返回验证码已过期] +J --> |否| L{验证码是否匹配?} +L --> |否| M[返回验证码错误] +L --> |是| N[验证通过,继续登录流程] +``` + +**Diagram sources** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java#L29-L54) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java#L52-L83) + +**Section sources** +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java#L1-L73) +- [VerificationUtil.java](file://datavines-server/src/main/java/io/datavines/server/utils/VerificationUtil.java#L1-L87) + +## 接口权限控制 + +DataVines服务器通过自定义注解和Spring拦截器实现了灵活的接口权限控制机制。核心是`AuthenticationInterceptor`拦截器,它在每个请求到达控制器之前进行身份验证和权限检查。 + +### 权限控制注解 + +系统提供了两个关键的注解来控制接口的访问权限: + +#### @AuthIgnore 注解 + +`@AuthIgnore`注解用于标记不需要身份验证的公共接口。例如,登录、注册和获取验证码等接口需要被公开访问。 + +```java +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthIgnore { +} +``` + +当`AuthenticationInterceptor`检测到一个方法被`@AuthIgnore`注解标记时,它会直接放行该请求,不进行任何令牌验证。 + +#### @CheckTokenExist 注解 + +`@CheckTokenExist`注解用于标记需要检查令牌是否存在的接口。与基本的令牌验证不同,此注解会调用`AccessTokenService`服务来检查令牌是否在数据库中存在且未被禁用,提供了更严格的访问控制。 + +```java +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckTokenExist { +} +``` + +### 拦截器工作流程 + +`AuthenticationInterceptor`是权限控制的核心,它实现了`HandlerInterceptor`接口,并在`preHandle`方法中执行权限检查逻辑。 + +```mermaid +flowchart TD +A[请求到达] --> B{方法是否有@AuthIgnore注解?} +B --> |是| C[放行请求] +B --> |否| D[从请求头或参数中获取令牌] +D --> E{令牌是否存在?} +E --> |否| F[抛出TOKEN_IS_NULL_ERROR异常] +E --> |是| G{方法是否有@CheckTokenExist注解?} +G --> |是| H[调用AccessTokenService检查令牌是否存在] +H --> I{令牌是否存在?} +I --> |否| J[抛出INVALID_TOKEN异常] +I --> |是| K[继续] +G --> |否| K[继续] +K --> L[从令牌中解析用户名] +L --> M[查询用户信息] +M --> N{用户是否存在?} +N --> |否| O[抛出INVALID_TOKEN异常] +N --> |是| P[将用户信息存入请求属性] +P --> Q[验证令牌的有效性] +Q --> R{令牌是否有效?} +R --> |否| S[抛出INVALID_TOKEN异常] +R --> |是| T[设置上下文,放行请求] +``` + +**Diagram sources** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L54-L104) +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java#L24-L27) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java#L24-L27) + +**Section sources** +- [AuthenticationInterceptor.java](file://datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java#L42-L116) +- [AuthIgnore.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java#L1-L28) +- [CheckTokenExist.java](file://datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java#L1-L27) + +## 安全策略配置 + +除了核心的认证和权限控制,DataVines服务器还配置了多项安全策略来增强整体安全性。 + +### Web安全配置 + +`WebMvcConfig`类配置了全局的Web安全策略,包括跨域资源共享(CORS)和资源处理器。 + +#### CORS配置 + +系统通过`CorsFilter`允许所有来源的跨域请求,这在开发环境中非常方便,但在生产环境中应限制为特定的可信来源。 + +```java +private CorsConfiguration addCorsConfig() { + CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*")); + corsConfiguration.addAllowedHeader("*"); + corsConfiguration.addAllowedMethod("*"); + corsConfiguration.setAllowCredentials(true); + return corsConfiguration; +} +``` + +#### 拦截器配置 + +`WebMvcConfig`注册了`AuthenticationInterceptor`,并配置了需要拦截的路径模式。所有以`/api/v1/`开头的API请求都会被拦截,但`/api/v1/login`路径被排除在外,允许匿名访问。 + +```java +registry.addInterceptor(loginRequiredInterceptor()) + .addPathPatterns(DataVinesConstants.BASE_API_PATH + "/**") + .excludePathPatterns(DataVinesConstants.BASE_API_PATH + "/login"); +``` + +### 敏感信息保护 + +DataVines服务器通过多种机制保护敏感信息,防止密码等机密数据在日志中泄露。 + +#### 日志脱敏 + +`SensitiveDataConverter`是一个Logback转换器,它使用正则表达式匹配日志中的密码字段,并将其替换为`******`。 + +```java +public static final String DATASOURCE_PASSWORD_REGEX = "(?<=(\\\\\"password\\\\\":\\\\\")).*?(?=(\\\\\"))"; +``` + +`PasswordFilterUtils`类提供了具体的脱敏逻辑,`SensitiveLogUtils`则负责将匹配到的密码字符串替换为掩码。 + +**Section sources** +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java#L35-L101) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java#L1-L60) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java#L1-L76) + +## 生产环境安全加固建议 + +为了在生产环境中确保DataVines服务器的安全性,建议采取以下加固措施: + +### HTTPS配置 + +在生产环境中,必须使用HTTPS来加密所有客户端与服务器之间的通信,防止令牌和敏感数据被窃听。 + +1. **配置SSL/TLS**:在`application.yaml`中配置服务器的SSL证书和私钥。 +2. **强制HTTPS**:配置Web服务器(如Nginx)将所有HTTP请求重定向到HTTPS。 +3. **使用强加密套件**:禁用弱加密算法(如SSLv3、TLS 1.0),仅启用TLS 1.2及以上版本。 + +虽然当前代码库中没有直接的HTTPS服务器配置,但`HttpUtils`类已经为客户端请求配置了安全的SSL上下文,信任所有证书(在生产环境中应配置为信任特定的CA证书)。 + +```java +static { + try { + ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS); + ctx.init(null, new TrustManager[]{XTM}, null); + } catch (NoSuchAlgorithmException e) { + logger.error("SSLContext init with NoSuchAlgorithmException", e); + } catch (KeyManagementException e) { + logger.error("SSLContext init with KeyManagementException", e); + } + SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE); + ... +} +``` + +### 敏感信息加密 + +生产环境中的敏感配置信息(如数据库密码、JWT密钥)不应以明文形式存储。 + +1. **加密配置文件**:使用`CryptionUtils`类提供的AES加密功能对`application.yaml`中的敏感字段进行加密。 +2. **环境变量**:将最敏感的密钥(如`jwt.token.secret`)通过环境变量注入,而不是写在配置文件中。 +3. **密钥管理服务**:对于高安全要求的环境,考虑使用AWS KMS、Hashicorp Vault等专业密钥管理服务。 + +### 其他最佳实践 + +- **定期轮换密钥**:定期更换JWT签名密钥和数据库密码。 +- **最小权限原则**:数据库用户应仅拥有执行必要操作的最小权限。 +- **安全审计**:启用详细的访问日志,定期审查可疑活动。 +- **输入验证**:对所有API输入进行严格的验证,防止注入攻击。 +- **更新依赖**:定期更新`pom.xml`中的第三方库,修复已知的安全漏洞。 + +**Section sources** +- [HttpUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/HttpUtils.java#L78-L122) +- [CryptionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java#L1-L66) + +## 总结 + +DataVines服务器的安全配置体系是一个多层次、多组件的综合系统。它以JWT认证为核心,结合验证码机制和细粒度的注解权限控制,构建了一个健壮的安全防线。通过`TokenManager`、`KaptchaConfig`和`AuthenticationInterceptor`等组件的协同工作,系统能够有效地验证用户身份并保护API接口。 + +在生产环境中部署时,必须超越默认配置,实施HTTPS加密、敏感信息保护和严格的访问控制策略。通过遵循本文档中的最佳实践,可以显著提升DataVines服务器的整体安全性,保护数据资产免受未授权访问和网络攻击。 + +[无来源,此部分为总结性内容] \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\346\200\247\350\203\275\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\346\200\247\350\203\275\351\205\215\347\275\256.md" new file mode 100644 index 00000000..46cf0d2c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\346\200\247\350\203\275\351\205\215\347\275\256.md" @@ -0,0 +1,507 @@ +# 性能配置 + + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [NamedThreadFactory.java](file://datavines-server/src/main/java/io/datavines/server/utils/NamedThreadFactory.java) +- [ThreadUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ThreadUtils.java) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [jmx_exporter_config.yaml](file://datavines-server/src/main/resources/jmx/jmx_exporter_config.yaml) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) + + +## 目录 +1. [引言](#引言) +2. [数据库连接池配置](#数据库连接池配置) +3. [线程池配置](#线程池配置) +4. [JVM与系统性能配置](#jvm与系统性能配置) +5. [缓存与注册中心配置](#缓存与注册中心配置) +6. [日志与监控配置](#日志与监控配置) +7. [不同规模部署的配置建议](#不同规模部署的配置建议) +8. [性能调优监控指标与方法](#性能调优监控指标与方法) +9. [结论](#结论) + +## 引言 + +DataVines 是一个数据质量监控平台,其性能表现受多种配置参数影响。本文档详细说明影响系统性能的关键配置,包括数据库连接池、线程池、JVM 参数、缓存机制等。通过合理调整这些配置参数,可以优化系统的吞吐量、响应时间和资源利用率。文档还提供了不同规模部署的配置建议,并介绍了性能调优的监控指标和方法。 + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +## 数据库连接池配置 + +DataVines 使用 HikariCP 作为主要的数据库连接池实现。在 `application.yaml` 配置文件中,可以找到详细的连接池配置参数: + +```yaml +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://127.0.0.1:5432/datavines + username: postgres + password: 123456 + hikari: + connection-test-query: select 1 + minimum-idle: 5 + auto-commit: true + validation-timeout: 3000 + pool-name: datavines + maximum-pool-size: 50 + connection-timeout: 30000 + idle-timeout: 600000 + leak-detection-threshold: 0 + initialization-fail-timeout: 1 +``` + +关键配置参数说明: +- **maximum-pool-size**: 最大连接数,设置为 50,可根据数据库承载能力和并发需求调整 +- **minimum-idle**: 最小空闲连接数,设置为 5,确保有足够连接随时可用 +- **connection-timeout**: 连接超时时间,30秒,超过此时间未获取到连接则抛出异常 +- **idle-timeout**: 空闲连接超时时间,10分钟,超过此时间的空闲连接将被关闭 +- **validation-timeout**: 连接验证超时时间,3秒,用于验证连接的有效性 +- **leak-detection-threshold**: 连接泄漏检测阈值,0表示禁用,建议生产环境设置合理值以检测连接泄漏 + +对于不同的数据库类型,DataVines 提供了多数据源支持。在 `application.yaml` 中通过 Spring Profiles 配置了 MySQL 支持: + +```yaml +--- +spring: + config: + activate: + on-profile: mysql + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/datavines?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: 123456 + quartz: + properties: + org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate +``` + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +## 线程池配置 + +DataVines 实现了多种线程池配置来处理并发任务,主要通过 `NamedThreadFactory` 和 `ThreadUtils` 工具类进行管理。 + +### NamedThreadFactory + +`NamedThreadFactory` 类用于创建命名的线程,便于监控和调试: + +```java +public class NamedThreadFactory implements ThreadFactory { + private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final ThreadGroup group; + private final String namePrefix; + private final boolean isDaemon; + + public NamedThreadFactory(String prefix, boolean daemon) { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); + namePrefix = prefix + "-" + POOL_NUMBER.getAndIncrement() + "-thread-"; + isDaemon = daemon; + } + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); + t.setDaemon(isDaemon); + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } +} +``` + +### ThreadUtils + +`ThreadUtils` 类提供了多种线程池创建方法: + +```java +public class ThreadUtils { + public static ThreadPoolExecutor newDaemonCachedThreadPool(String prefix) { + ThreadFactory threadFactory = namedThreadFactory(prefix); + return ((ThreadPoolExecutor) Executors.newCachedThreadPool(threadFactory)); + } + + public static ThreadPoolExecutor newDaemonFixedThreadPool(int nThreads, String prefix) { + ThreadFactory threadFactory = namedThreadFactory(prefix); + return ((ThreadPoolExecutor) Executors.newFixedThreadPool(nThreads, threadFactory)); + } + + public static ScheduledExecutorService newDaemonThreadScheduledExecutor(String threadName, int corePoolSize) { + return newThreadScheduledExecutor(threadName, corePoolSize, true); + } +} +``` + +这些线程池配置用于处理各种异步任务,包括任务调度、数据处理和API请求等。 + +**本文档引用的文件** +- [NamedThreadFactory.java](file://datavines-server/src/main/java/io/datavines/server/utils/NamedThreadFactory.java) +- [ThreadUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ThreadUtils.java) + +## JVM与系统性能配置 + +DataVines 的 JVM 配置在启动脚本 `datavines-daemon.sh` 中定义,这些配置对系统性能有重要影响。 + +### JVM 参数配置 + +在 `bin/datavines-daemon.sh` 脚本中,设置了以下 JVM 参数: + +```bash +export DATAVINES_OPTS="-server -Xmx16g -Xms1g -XX:+UseG1GC -XX:G1HeapRegionSize=8M" +``` + +关键 JVM 参数说明: +- **-server**: 使用服务器模式的 JVM,优化长期运行的应用程序 +- **-Xmx16g**: 最大堆内存设置为 16GB,可根据服务器物理内存调整 +- **-Xms1g**: 初始堆内存设置为 1GB,避免频繁的堆扩展 +- **-XX:+UseG1GC**: 使用 G1 垃圾收集器,适合大内存应用,减少停顿时间 +- **-XX:G1HeapRegionSize=8M**: 设置 G1 区域大小为 8MB,优化垃圾收集性能 + +### 系统资源监控 + +`OSUtils` 类提供了系统资源监控功能,用于监控内存使用情况和系统负载: + +```java +public class OSUtils { + public static double memoryUsage() { + GlobalMemory memory = hal.getMemory(); + double memoryUsage = (memory.getTotal() - memory.getAvailable() - memory.getVirtualMemory().getSwapUsed()) * 0.1 / memory.getTotal() * 10; + DecimalFormat df = new DecimalFormat(TWO_DECIMAL); + df.setRoundingMode(RoundingMode.HALF_UP); + return Double.parseDouble(df.format(memoryUsage)); + } + + public static double availablePhysicalMemorySize() { + double availablePhysicalMemorySize; + if (CommonConstants.KUBERNETES_MODE) { + long freeMemory = Runtime.getRuntime().freeMemory(); + availablePhysicalMemorySize = freeMemory /1024.0/1024/1024; + } else { + GlobalMemory memory = hal.getMemory(); + availablePhysicalMemorySize = (memory.getAvailable() + memory.getVirtualMemory().getSwapUsed()) /1024.0/1024/1024; + } + DecimalFormat df = new DecimalFormat(TWO_DECIMAL); + df.setRoundingMode(RoundingMode.HALF_UP); + return Double.parseDouble(df.format(availablePhysicalMemorySize)); + } +} +``` + +这些监控功能帮助系统判断当前资源使用情况,避免在高负载下执行资源密集型任务。 + +**本文档引用的文件** +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) +- [OSUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/OSUtils.java) + +## 缓存与注册中心配置 + +DataVines 使用多种缓存机制和注册中心来提高系统性能和可用性。 + +### ZooKeeper 注册中心 + +DataVines 支持使用 ZooKeeper 作为注册中心,相关配置在 `common.properties` 文件中: + +```properties +#registry.type=zookeeper +#registry.zookeeper.server.list=localhost:2181 +#registry.failover.key=/datavines/failover +#registry.servers.key=/datavines/servers +``` + +在 `ZooKeeperRegistry.java` 中实现了注册中心的具体逻辑: + +```java +@Override +public void init(Properties properties) { + this.properties = properties; + ZooKeeperClient zooKeeperClient = null; + try { + ZooKeeperConfig zooKeeperConfig = new ZooKeeperConfig(); + zooKeeperConfig.setServerList(properties.getProperty(CommonPropertyUtils.REGISTRY_ZOOKEEPER_SERVER_LIST, + CommonPropertyUtils.REGISTRY_ZOOKEEPER_SERVER_LIST_DEFAULT)); + zooKeeperClient = ZooKeeperClient.getInstance().buildClient(zooKeeperConfig); + client = zooKeeperClient.getClient(); + ServerInfo serverInfo = new ServerInfo(NetUtils.getHost(), + Integer.valueOf((String) properties.get("server.port")), + new Timestamp(System.currentTimeMillis()), new Timestamp(System.currentTimeMillis())); + String serverKey = properties.getProperty(CommonPropertyUtils.SERVERS_KEY, CommonPropertyUtils.SERVERS_KEY_DEFAULT); + put(serverKey, serverInfo.toString(), true); + treeCacheMap.put(serverKey, new TreeCache(client, serverKey)); + } catch (Exception exception) { + logger.error("build zookeeper client error: {0} ", exception); + } +} +``` + +### 内部缓存机制 + +DataVines 在多个组件中实现了内部缓存机制,如 `JdbcDataSourceManager` 中的连接池缓存: + +```java +private final Map dataSourceMap = new ConcurrentHashMap<>(); + +public synchronized DataSource getDataSource(BaseJdbcDataSourceInfo baseJdbcDataSourceInfo) throws SQLException { + HikariDataSource dataSource = dataSourceMap.get(baseJdbcDataSourceInfo.getUniqueKey()); + if (dataSource == null) { + synchronized (JdbcDataSourceManager.class) { + dataSource = dataSourceMap.get(baseJdbcDataSourceInfo.getUniqueKey()); + if (dataSource == null) { + HikariConfig hikariConfig = new HikariConfig(); + hikariConfig.setJdbcUrl(baseJdbcDataSourceInfo.getJdbcUrl()); + hikariConfig.setUsername(baseJdbcDataSourceInfo.getUser()); + hikariConfig.setPassword(StringUtils.isEmptyOrNullStr(baseJdbcDataSourceInfo.getPassword()) ? null : baseJdbcDataSourceInfo.getPassword()); + hikariConfig.setDriverClassName(baseJdbcDataSourceInfo.getDriverClass()); + hikariConfig.setMaximumPoolSize(10); + HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig); + dataSourceMap.put(baseJdbcDataSourceInfo.getUniqueKey(), hikariDataSource); + return hikariDataSource; + } + } + } + return dataSource; +} +``` + +**本文档引用的文件** +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [ZooKeeperRegistry.java](file://datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +## 日志与监控配置 + +DataVines 提供了完善的日志和监控配置,帮助运维人员了解系统运行状态。 + +### 日志配置 + +`server-logback.xml` 配置文件定义了日志输出格式和策略: + +```xml + + + + + [%level] %date{yyyy-MM-dd HH:mm:ss.SSS} %logger{96}:[%line] - %msg%n + UTF-8 + + + + + ${log.base}/datavines-server.log + + ${log.base}/datavines-server.%d{yyyy-MM-dd_HH}.%i.log + 168 + 200MB + + + [%level] %date{yyyy-MM-dd HH:mm:ss.SSS} %logger{96}:[%line] - %msg%n + UTF-8 + + + +``` + +关键日志配置: +- **scan="true"**: 启用配置文件热加载 +- **scanPeriod="120 seconds"**: 每 120 秒检查配置文件变化 +- **SizeAndTimeBasedRollingPolicy**: 基于时间和大小的滚动策略 +- **maxFileSize="200MB"**: 单个日志文件最大 200MB +- **maxHistory="168"**: 保留最近 168 个日志文件(约一周) + +### JMX 监控配置 + +DataVines 集成了 JMX 监控,通过 `jmx_exporter_config.yaml` 配置文件暴露系统指标: + +```yaml +--- +lowercaseOutputLabelNames: true +lowercaseOutputName: true +whitelistObjectNames: ["java.lang:type=OperatingSystem"] +blacklistObjectNames: [] +rules: + - pattern: 'java.lang<>(committed_virtual_memory|free_physical_memory|free_swap_space|total_physical_memory|total_swap_space)_size:' + name: os_$1_bytes + type: GAUGE + attrNameSnakeCase: true + - pattern: 'java.lang<>((?!process_cpu_time)\w+):' + name: os_$1 + type: GAUGE + attrNameSnakeCase: true +``` + +在启动脚本中通过 Java Agent 启用 JMX 监控: + +```bash +JMX="-javaagent:$DATAVINES_HOME/libs/jmx_prometheus_javaagent-0.20.0.jar=10010:$DATAVINES_CONF_DIR/jmx/jmx_exporter_config.yaml" +``` + +这使得系统可以暴露操作系统级别的监控指标,如内存使用、CPU 负载等。 + +**本文档引用的文件** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [jmx_exporter_config.yaml](file://datavines-server/src/main/resources/jmx/jmx_exporter_config.yaml) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) + +## 不同规模部署的配置建议 + +根据不同的部署规模,建议采用不同的性能配置策略。 + +### 小规模部署(开发/测试环境) + +适用于单机部署,用户量小于 100,数据量较小的场景: + +```yaml +# application.yaml +spring: + datasource: + hikari: + maximum-pool-size: 20 + minimum-idle: 2 + connection-timeout: 30000 + idle-timeout: 600000 + +# datavines-daemon.sh +export DATAVINES_OPTS="-server -Xmx4g -Xms512m -XX:+UseG1GC" +``` + +### 中等规模部署(生产环境,中等负载) + +适用于 3-5 节点集群,用户量 100-1000,中等数据量的生产环境: + +```yaml +# application.yaml +spring: + datasource: + hikari: + maximum-pool-size: 50 + minimum-idle: 10 + connection-timeout: 30000 + idle-timeout: 600000 + validation-timeout: 5000 + +# datavines-daemon.sh +export DATAVINES_OPTS="-server -Xmx16g -Xms2g -XX:+UseG1GC -XX:G1HeapRegionSize=8M -XX:MaxGCPauseMillis=200" +``` + +### 大规模部署(高并发生产环境) + +适用于大型集群,用户量超过 1000,大数据量的高并发场景: + +```yaml +# application.yaml +spring: + datasource: + hikari: + maximum-pool-size: 100 + minimum-idle: 20 + connection-timeout: 15000 + idle-timeout: 300000 + validation-timeout: 3000 + max-lifetime: 1800000 + keepalive-time: 600000 + +# datavines-daemon.sh +export DATAVINES_OPTS="-server -Xmx32g -Xms8g -XX:+UseG1GC -XX:G1HeapRegionSize=16M -XX:MaxGCPauseMillis=100 -XX:+UseStringDeduplication" +``` + +### 配置调整原则 + +1. **数据库连接池**: 根据数据库服务器的连接数限制和应用并发需求调整 +2. **JVM 堆内存**: 建议设置为物理内存的 50-70%,避免过度占用系统内存 +3. **垃圾收集器**: G1GC 适合大内存应用,CMS 适合低延迟要求的场景 +4. **线程池**: 根据 CPU 核心数和任务类型合理设置线程数 + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) + +## 性能调优监控指标与方法 + +为了有效进行性能调优,需要监控关键指标并采用科学的方法。 + +### 关键监控指标 + +#### 系统级别指标 +- CPU 使用率 +- 内存使用率 +- 磁盘 I/O +- 网络带宽 + +#### JVM 级别指标 +- 堆内存使用情况 +- GC 暂停时间 +- GC 频率 +- 线程数量 + +#### 应用级别指标 +- 数据库连接池使用率 +- 请求响应时间 +- 系统吞吐量 +- 错误率 + +### 监控方法 + +#### 内置监控 +DataVines 通过 JMX 暴露了丰富的监控指标,可以通过 Prometheus 等工具采集: + +```yaml +# jmx_exporter_config.yaml +rules: + - pattern: 'java.lang<>(committed_virtual_memory|free_physical_memory|free_swap_space|total_physical_memory|total_swap_space)_size:' + name: os_$1_bytes + type: GAUGE +``` + +#### 日志分析 +通过分析 `server-logback.xml` 配置的日志文件,可以了解系统运行状况: + +```xml + + ${log.base}/datavines-server.log + + ${log.base}/datavines-server.%d{yyyy-MM-dd_HH}.%i.log + 168 + 200MB + + +``` + +#### 性能测试 +建议使用以下方法进行性能测试: +1. **基准测试**: 测量系统在标准负载下的性能表现 +2. **压力测试**: 测试系统在高负载下的稳定性和性能 +3. **负载测试**: 模拟实际使用场景的负载模式 +4. **稳定性测试**: 长时间运行测试系统的稳定性 + +### 调优方法 + +1. **渐进式调整**: 每次只调整一个参数,观察效果 +2. **监控驱动**: 基于监控数据进行决策,而非猜测 +3. **记录变更**: 详细记录每次配置变更及其效果 +4. **回滚计划**: 准备好回滚方案,以防新配置导致问题 + +**本文档引用的文件** +- [jmx_exporter_config.yaml](file://datavines-server/src/main/resources/jmx/jmx_exporter_config.yaml) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +## 结论 + +DataVines 的性能配置涉及多个方面,包括数据库连接池、线程池、JVM 参数、缓存机制和监控系统。通过合理配置这些参数,可以显著提升系统的性能和稳定性。 + +关键要点总结: +1. **数据库连接池**: 根据实际负载调整最大连接数和超时参数 +2. **线程池**: 使用合适的线程池类型和大小,避免资源浪费 +3. **JVM 配置**: 选择合适的垃圾收集器和内存设置 +4. **监控系统**: 充分利用内置的 JMX 和日志监控功能 +5. **配置策略**: 根据部署规模采用不同的配置策略 + +建议在生产环境中逐步调整配置参数,并通过监控系统持续观察效果,确保系统稳定高效运行。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\346\227\245\345\277\227\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\346\227\245\345\277\227\351\205\215\347\275\256.md" new file mode 100644 index 00000000..66de464d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\346\227\245\345\277\227\351\205\215\347\275\256.md" @@ -0,0 +1,262 @@ +# 日志配置 + + +**本文档引用的文件** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java) +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java) +- [ServerLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/ServerLogFilter.java) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [LoggerUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/LoggerUtils.java) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + + +## 目录 +1. [日志配置概述](#日志配置概述) +2. [logback.xml 配置结构](#logbackxml-配置结构) +3. [日志级别设置](#日志级别设置) +4. [日志文件滚动策略](#日志文件滚动策略) +5. [日志输出格式](#日志输出格式) +6. [作业执行日志与服务器运行日志分离](#作业执行日志与服务器运行日志分离) +7. [敏感信息过滤机制](#敏感信息过滤机制) +8. [日志系统在问题排查与监控中的应用](#日志系统在问题排查与监控中的应用) + +## 日志配置概述 + +DataVines 服务器的日志系统基于 Logback 实现,通过 `server-logback.xml` 文件进行配置。该系统支持控制台输出、文件输出,并实现了作业执行日志与服务器运行日志的分离。同时,系统内置了敏感信息过滤机制,能够自动对日志中的密码等敏感数据进行脱敏处理,保障系统安全。 + +**日志配置文件** +日志配置由 `datavines-server/src/main/resources/server-logback.xml` 定义,并在 `application.yaml` 中通过 `logging.config` 属性指定加载路径。 + +```mermaid +graph TD +A[日志配置] --> B[server-logback.xml] +A --> C[application.yaml] +B --> D[控制台输出] +B --> E[文件输出] +B --> F[日志分离] +B --> G[敏感信息过滤] +``` + +**图源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +## logback.xml 配置结构 + +`server-logback.xml` 是 DataVines 服务器的核心日志配置文件,其主要结构包括: + +- **根配置**:`` 标签,启用了配置扫描(`scan="true"`)和扫描周期(`scanPeriod="120 seconds"`),允许在不重启服务的情况下动态更新日志配置。 +- **日志基础路径**:通过 `` 定义日志文件的存储根目录。 +- **Appender 配置**:定义了三种日志输出方式: + - `STDOUT`:将日志输出到控制台。 + - `JOB_LOG_FILE`:使用 `SiftingAppender` 为每个作业执行生成独立的日志文件。 + - `SERVER_LOG_FILE`:将服务器运行日志输出到滚动文件中。 +- **Root Logger**:将上述三个 Appender 绑定到根日志记录器,并设置日志级别为 `INFO`。 + +```mermaid +classDiagram +class LogbackConfiguration { ++String log.base = "logs" ++scan : true ++scanPeriod : "120 seconds" +} +class Appender { ++STDOUT : ConsoleAppender ++JOB_LOG_FILE : SiftingAppender ++SERVER_LOG_FILE : RollingFileAppender +} +class RootLogger { ++level : "INFO" ++appender-ref : STDOUT ++appender-ref : JOB_LOG_FILE ++appender-ref : SERVER_LOG_FILE +} +LogbackConfiguration --> Appender +LogbackConfiguration --> RootLogger +``` + +**图源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +**节源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +## 日志级别设置 + +DataVines 的日志级别遵循标准的 Logback 级别体系,从高到低依次为:`ERROR`、`WARN`、`INFO`、`DEBUG`、`TRACE`。 + +在 `server-logback.xml` 中,根日志记录器的级别被设置为 `INFO`,这意味着 `INFO` 及以上级别的日志(`INFO`、`WARN`、`ERROR`)将被记录。 + +此外,`JOB_LOG_FILE` Appender 中配置了 `ThresholdFilter`,其级别也设置为 `INFO`,确保只有 `INFO` 及以上级别的日志才会被写入作业日志文件。 + +```xml + + + + + +``` + +**节源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +## 日志文件滚动策略 + +服务器运行日志(`SERVER_LOG_FILE`)采用了基于时间和大小的双重滚动策略(`SizeAndTimeBasedRollingPolicy`),具体配置如下: + +- **文件名模式**:`${log.base}/datavines-server.%d{yyyy-MM-dd_HH}.%i.log` + - 按小时(`%d{yyyy-MM-dd_HH}`)进行滚动。 + - 当文件大小达到上限时,会在同一小时内生成新的文件(`%i` 为索引)。 +- **最大历史文件数**:`168`,保留最近 168 小时(7 天)的日志文件。 +- **单个文件最大大小**:`200MB`,当文件达到 200MB 时会触发滚动。 + +这种策略确保了日志文件不会无限增长,便于管理和归档。 + +```mermaid +flowchart TD +A[开始写入日志] --> B{文件大小 >= 200MB?} +B --> |是| C[创建新文件,索引+1] +B --> |否| D{时间到下一小时?} +D --> |是| E[创建新小时文件] +D --> |否| F[继续写入当前文件] +C --> G[继续写入] +E --> G +G --> B +``` + +**图源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +**节源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +## 日志输出格式 + +DataVines 定义了统一的日志输出格式,适用于控制台和文件输出。格式定义在 `` 标签内: + +```xml +[%level] %date{yyyy-MM-dd HH:mm:ss.SSS} %logger{96}:[%line] - %msg%n +``` + +该格式包含以下信息: +- `[%level]`:日志级别(如 `[INFO]`)。 +- `%date{yyyy-MM-dd HH:mm:ss.SSS}`:精确到毫秒的时间戳。 +- `%logger{96}`:记录日志的类名(最多 96 个字符)。 +- `[%line]`:日志语句在源代码中的行号。 +- `- %msg%n`:日志消息内容和换行符。 + +此格式清晰、完整,便于阅读和解析。 + +**节源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +## 作业执行日志与服务器运行日志分离 + +DataVines 通过巧妙的配置实现了作业执行日志与服务器运行日志的完全分离。 + +### 作业执行日志分离机制 + +作业执行日志的分离依赖于 Logback 的 `SiftingAppender`(筛选追加器)和自定义的 `Discriminator`(鉴别器)。 + +1. **SiftingAppender (`JOB_LOG_FILE`)**:这是一个多路复用的 Appender,它可以根据一个“鉴别值”(discriminating value)动态地创建多个子 Appender。 +2. **Discriminator (`JobExecutionLogDiscriminator`)**:该类继承自 `AbstractDiscriminator`,其核心方法 `getDiscriminatingValue(ILoggingEvent event)` 决定了日志的分流依据。 + - 它从日志事件的 `loggerName` 中提取出 `jobExecutionUniqueId`。 + - 这个 `jobExecutionUniqueId` 通常是一个包含作业ID、执行时间等信息的唯一标识符。 + - 该方法返回的值(如 `job-12345`)将作为 `SiftingAppender` 创建子文件的依据。 +3. **Sift 配置**:在 `` 标签内,定义了一个模板 Appender。`${jobExecutionUniqueId}` 会被 `Discriminator` 返回的实际值替换,从而为每个作业执行创建一个独立的日志文件(如 `logs/job-12345.log`)。 + +### 服务器运行日志分离机制 + +服务器运行日志的分离则通过 `ServerLogFilter` 实现。 + +- `ServerLogFilter` 是一个自定义的 `Filter`,其 `decide` 方法会检查日志事件的线程名。 +- 只有当线程名以 `"Server-"` 开头时,该日志才会被 `SERVER_LOG_FILE` Appender 接受(`FilterReply.ACCEPT`),否则被拒绝(`FilterReply.DENY`)。 +- 这样,只有服务器核心线程产生的日志才会被写入 `datavines-server.log` 文件。 + +```mermaid +sequenceDiagram +participant Application as 应用程序 +participant SiftingAppender as SiftingAppender(JOB_LOG_FILE) +participant Discriminator as JobExecutionLogDiscriminator +participant FileAppender as FileAppender(job-12345.log) +Application->>SiftingAppender : 发送日志事件 +SiftingAppender->>Discriminator : getDiscriminatingValue(event) +Discriminator-->>SiftingAppender : 返回 "job-12345" +SiftingAppender->>SiftingAppender : 查找或创建 "FILE-job-12345" Appender +SiftingAppender->>FileAppender : 写入日志 +``` + +**图源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java) + +**节源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [JobExecutionLogDiscriminator.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogDiscriminator.java) +- [JobExecutionLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java) +- [ServerLogFilter.java](file://datavines-common/src/main/java/io/datavines/common/log/ServerLogFilter.java) + +## 敏感信息过滤机制 + +DataVines 内置了敏感信息过滤机制,能够自动对日志中出现的密码等敏感数据进行脱敏处理。 + +### 实现原理 + +该机制的核心是 `SensitiveDataConverter` 类,它通过 Logback 的 `conversionRule` 机制被集成到日志格式化流程中。 + +1. **注册转换器**:在 `server-logback.xml` 中,通过 `` 将 `message` 关键字映射到 `SensitiveDataConverter` 类。 +2. **重写消息格式**:在 `JOB_LOG_FILE` 的 `` 中,使用 `%message%n` 而不是 `%msg%n`。这使得日志消息会经过 `SensitiveDataConverter` 的处理。 +3. **正则表达式匹配**:`SensitiveDataConverter` 内部定义了正则表达式(如 `DATASOURCE_PASSWORD_REGEX`),用于匹配 JSON 格式日志中 `"password":"..."` 的模式。 +4. **脱敏处理**:`convert` 方法会获取原始日志消息,然后调用 `PasswordFilterUtils.convertPassword` 方法,使用正则表达式查找并替换所有匹配的密码字段。 +5. **掩码实现**:`SensitiveLogUtils.maskDataSourcePwd` 方法将匹配到的密码字符串替换为固定的掩码字符串 `******`。 + +### 配置方法 + +此机制是内置且默认启用的,无需额外配置。只要日志消息中包含符合预定义正则表达式的敏感信息,就会被自动脱敏。 + +```mermaid +flowchart LR +A[原始日志消息] --> B{包含密码?} +B --> |是| C[应用正则表达式] +C --> D[匹配 "password":"123456"] +D --> E[替换为 "password":"******"] +E --> F[输出脱敏日志] +B --> |否| F +``` + +**图源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java) + +**节源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [PasswordFilterUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java) + +## 日志系统在问题排查与监控中的应用 + +DataVines 的日志系统为问题排查和系统监控提供了强有力的支持。 + +### 问题排查 + +- **精准定位**:通过分离的作业日志,可以快速定位到特定作业执行的完整日志流,无需在庞大的服务器日志中搜索。 +- **上下文完整**:日志格式包含时间、类名、行号等信息,便于开发者快速定位代码位置。 +- **敏感信息保护**:脱敏机制确保了排查问题时不会意外暴露数据库密码等敏感信息,符合安全审计要求。 + +### 系统监控 + +- **日志轮转**:基于时间和大小的滚动策略,保证了日志文件的可管理性,防止磁盘空间被耗尽。 +- **动态配置**:`scan="true"` 允许运维人员在不重启服务的情况下调整日志级别(例如,临时将级别调为 `DEBUG` 以获取更详细的调试信息)。 +- **多渠道输出**:同时输出到控制台和文件,方便在开发调试和生产环境监控中使用。 + +通过合理利用这些日志特性,运维和开发团队可以高效地维护 DataVines 服务器的稳定运行。 + +**节源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [LoggerUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/LoggerUtils.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256.md" new file mode 100644 index 00000000..c4b7d19f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256/\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256.md" @@ -0,0 +1,356 @@ +# 服务器配置 + + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [JacksonConfig.java](file://datavines-server/src/main/java/io/datavines/server/config/JacksonConfig.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [DataVinesConstants.java](file://datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java) +- [datavines-daemon.sh](file://bin/datavines-daemon.sh) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +DataVines 是一个数据质量监控平台,提供数据校验、监控和告警功能。本配置文档详细说明了 DataVines 服务器的所有配置选项,包括服务器端口、线程池配置、日志配置、安全配置(如 JWT、验证码)、跨域配置等。文档解释了 application.yaml 中各个配置项的作用、可选值和默认值,提供了配置示例和最佳实践,特别是生产环境下的安全配置建议。同时,文档还说明了配置的加载机制和优先级,以及如何通过环境变量覆盖配置文件中的值。 + +## 项目结构 +DataVines 项目采用模块化设计,主要包含以下模块: +- **datavines-cli**: 命令行工具 +- **datavines-client**: HTTP 客户端 +- **datavines-common**: 公共组件和工具类 +- **datavines-connector**: 数据源连接器 +- **datavines-core**: 核心功能 +- **datavines-engine**: 执行引擎 +- **datavines-metric**: 指标定义 +- **datavines-notification**: 通知服务 +- **datavines-registry**: 注册中心 +- **datavines-runner**: 任务执行器 +- **datavines-server**: 服务器端 +- **datavines-spi**: SPI 接口 +- **datavines-ui**: 用户界面 + +服务器配置主要集中在 `datavines-server` 模块中,包括 `application.yaml` 配置文件、日志配置、安全配置等。 + +```mermaid +graph TB +subgraph "前端" +UI[用户界面] +end +subgraph "后端" +API[API 服务器] +Auth[认证服务] +DB[(数据库)] +end +UI --> API +API --> Auth +API --> DB +``` + +**图表来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +## 核心组件 +DataVines 服务器的核心组件包括: +- **Spring Boot**: 作为基础框架 +- **MyBatis-Plus**: ORM 框架 +- **Quartz**: 任务调度 +- **JWT**: 认证机制 +- **Kaptcha**: 验证码生成 +- **Logback**: 日志框架 + +这些组件通过 `application.yaml` 配置文件进行配置,确保系统的稳定运行和高效管理。 + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [JacksonConfig.java](file://datavines-server/src/main/java/io/datavines/server/config/JacksonConfig.java) + +## 架构概述 +DataVines 服务器采用微服务架构,通过 Spring Boot 实现。系统通过 `application.yaml` 配置文件管理各种配置项,包括数据库连接、任务调度、日志记录等。认证机制采用 JWT,确保用户身份的安全性。验证码通过 Kaptcha 生成,增强系统的安全性。日志记录使用 Logback,支持多种日志级别和输出格式。 + +```mermaid +classDiagram +class DataVinesServer { ++main(String[] args) void +} +class WebMvcConfig { ++addInterceptors(InterceptorRegistry) void ++addResourceHandlers(ResourceHandlerRegistry) void ++addViewControllers(ViewControllerRegistry) void ++localeResolver() LocaleResolver ++corsFilter() CorsFilter +} +class TokenManager { ++generateToken(String, String) String ++validateToken(String, String, String) boolean ++getClaims(String) Claims +} +class KaptchaConfig { ++captchaProducer() DefaultKaptcha +} +class JacksonConfig { ++jacksonLongToString() Jackson2ObjectMapperBuilderCustomizer +} +DataVinesServer --> WebMvcConfig : "使用" +DataVinesServer --> TokenManager : "使用" +DataVinesServer --> KaptchaConfig : "使用" +DataVinesServer --> JacksonConfig : "使用" +``` + +**图表来源** +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) +- [JacksonConfig.java](file://datavines-server/src/main/java/io/datavines/server/config/JacksonConfig.java) + +## 详细组件分析 + +### 服务器配置分析 +DataVines 服务器的配置主要通过 `application.yaml` 文件进行管理。以下是关键配置项的详细说明: + +#### 服务器端口配置 +```yaml +server: + port: 5600 +``` +- **作用**: 设置服务器监听的端口号。 +- **可选值**: 任意有效的端口号(1-65535)。 +- **默认值**: 5600。 +- **生产环境建议**: 使用非默认端口以增加安全性。 + +#### 数据库连接配置 +```yaml +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://127.0.0.1:5432/datavines + username: postgres + password: 123456 + hikari: + connection-test-query: select 1 + minimum-idle: 5 + auto-commit: true + validation-timeout: 3000 + pool-name: datavines + maximum-pool-size: 50 + connection-timeout: 30000 + idle-timeout: 600000 + leak-detection-threshold: 0 + initialization-fail-timeout: 1 +``` +- **作用**: 配置数据库连接信息,包括驱动类名、URL、用户名、密码以及 HikariCP 连接池参数。 +- **可选值**: 根据使用的数据库类型选择相应的驱动类名和 URL。 +- **默认值**: PostgreSQL 数据库,端口 5432,数据库名 datavines,用户名 postgres,密码 123456。 +- **生产环境建议**: 使用强密码,配置合理的连接池大小,避免资源浪费。 + +#### 任务调度配置 +```yaml +spring: + quartz: + job-store-type: jdbc + jdbc: + initialize-schema: never + properties: + org.quartz.threadPool.threadPriority: 5 + org.quartz.jobStore.isClustered: true + org.quartz.jobStore.class: org.springframework.scheduling.quartz.LocalDataSourceJobStore + org.quartz.scheduler.instanceId: AUTO + org.quartz.jobStore.tablePrefix: QRTZ_ + org.quartz.jobStore.acquireTriggersWithinLock: true + org.quartz.scheduler.instanceName: datavines + org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool + org.quartz.threadPool.makeThreadsDaemons: true + org.quartz.threadPool.threadCount: 25 + org.quartz.jobStore.misfireThreshold: 60000 + org.quartz.scheduler.batchTriggerAcquisitionMaxCount: 1 + org.quartz.scheduler.makeSchedulerThreadDaemon: true + org.quartz.jobStore.useProperties: false + org.quartz.threadPool.threadCount: 25 + org.quartz.jobStore.misfireThreshold: 60000 + org.quartz.scheduler.batchTriggerAcquisitionMaxCount: 1 + org.quartz.scheduler.makeSchedulerThreadDaemon: true + org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate + org.quartz.jobStore.clusterCheckinInterval: 5000 +``` +- **作用**: 配置 Quartz 任务调度器,支持集群模式。 +- **可选值**: 根据实际需求调整线程池大小、任务存储方式等。 +- **默认值**: 使用 JDBC 存储任务,支持集群,线程池大小 25。 +- **生产环境建议**: 确保数据库连接稳定,合理配置线程池大小,避免任务积压。 + +#### 日志配置 +```yaml +logging: + config: classpath:server-logback.xml +``` +- **作用**: 指定日志配置文件的位置。 +- **可选值**: 任意有效的日志配置文件路径。 +- **默认值**: `classpath:server-logback.xml`。 +- **生产环境建议**: 配置详细的日志级别和输出格式,便于问题排查。 + +#### 安全配置 +```yaml +jwt: + token: + secret: asdqwe + timeout: 8640000 + algorithm: HS256 +``` +- **作用**: 配置 JWT 认证机制,包括密钥、超时时间和算法。 +- **可选值**: 密钥可以是任意字符串,超时时间单位为毫秒,算法支持 HS256、HS384、HS512 等。 +- **默认值**: 密钥 asdqwe,超时时间 8640000 毫秒(10 天),算法 HS256。 +- **生产环境建议**: 使用强密钥,缩短超时时间,提高安全性。 + +#### 验证码配置 +```yaml +kaptcha: + border: yes + border.color: 105,179,90 + textproducer.font.color: blue + image.width: 125 + image.height: 65 + textproducer.font.size: 45 + session.key: code + textproducer.char.length: 4 + textproducer.font.names: cmr10 +``` +- **作用**: 配置 Kaptcha 验证码生成器,包括边框、字体颜色、图片尺寸、字符长度等。 +- **可选值**: 根据实际需求调整各项参数。 +- **默认值**: 边框 yes,边框颜色 105,179,90,字体颜色 blue,图片宽度 125,高度 65,字体大小 45,会话键 code,字符长度 4,字体名称 cmr10。 +- **生产环境建议**: 调整验证码复杂度,防止自动化攻击。 + +#### 跨域配置 +```java +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", addCorsConfig()); + return new CorsFilter(source); + } + + private CorsConfiguration addCorsConfig() { + CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*")); + corsConfiguration.addAllowedHeader("*"); + corsConfiguration.addAllowedMethod("*"); + corsConfiguration.setAllowCredentials(true); + return corsConfiguration; + } +} +``` +- **作用**: 配置跨域资源共享(CORS),允许前端应用访问后端 API。 +- **可选值**: 根据实际需求调整允许的源、头信息、方法等。 +- **默认值**: 允许所有源、头信息和方法,支持凭据。 +- **生产环境建议**: 限制允许的源,避免安全风险。 + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [WebMvcConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/WebMvcConfig.java) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) +- [KaptchaConfig.java](file://datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java) + +### Jackson 配置分析 +```java +@Configuration +public class JacksonConfig { + @Bean + public Jackson2ObjectMapperBuilderCustomizer jacksonLongToString() { + return builder -> { + builder.serializerByType(Long.class, ToStringSerializer.instance); + builder.serializerByType(long.class, ToStringSerializer.instance); + builder.serializerByType(BigInteger.class, ToStringSerializer.instance); + builder.serializerByType(BigDecimal.class, ToStringSerializer.instance); + }; + } +} +``` +- **作用**: 配置 Jackson 序列化器,将长整型、大整数和大十进制数序列化为字符串,避免 JavaScript 中的精度丢失问题。 +- **可选值**: 无。 +- **默认值**: 启用长整型、大整数和大十进制数的字符串序列化。 +- **生产环境建议**: 保持启用,确保数据精度。 + +**章节来源** +- [JacksonConfig.java](file://datavines-server/src/main/java/io/datavines/server/config/JacksonConfig.java) + +## 依赖分析 +DataVines 服务器依赖于多个外部库和框架,包括 Spring Boot、MyBatis-Plus、Quartz、JWT、Kaptcha 和 Logback。这些依赖通过 Maven 管理,确保版本兼容性和稳定性。 + +```mermaid +graph TD +A[DataVines Server] --> B[Spring Boot] +A --> C[MyBatis-Plus] +A --> D[Quartz] +A --> E[JWT] +A --> F[Kaptcha] +A --> G[Logback] +B --> H[Spring Framework] +C --> I[MyBatis] +D --> J[Quartz Core] +E --> K[Java JWT] +F --> L[Kaptcha] +G --> M[SLF4J] +``` + +**图表来源** +- [pom.xml](file://datavines-server/pom.xml) + +**章节来源** +- [pom.xml](file://datavines-server/pom.xml) + +## 性能考虑 +为了确保 DataVines 服务器的高性能,建议采取以下措施: +- **优化数据库连接池**: 根据实际负载调整 HikariCP 连接池的大小,避免资源浪费。 +- **合理配置任务调度**: 调整 Quartz 线程池大小,确保任务能够及时执行。 +- **日志级别管理**: 在生产环境中使用适当的日志级别,减少不必要的日志输出。 +- **缓存机制**: 使用缓存减少数据库查询次数,提高响应速度。 +- **负载均衡**: 在高并发场景下,使用负载均衡器分散请求压力。 + +## 故障排除指南 +### 常见问题及解决方案 +1. **服务器启动失败** + - **原因**: 配置文件错误或依赖库缺失。 + - **解决方案**: 检查 `application.yaml` 文件中的配置项是否正确,确保所有依赖库已正确安装。 + +2. **数据库连接失败** + - **原因**: 数据库地址、端口、用户名或密码错误。 + - **解决方案**: 检查 `application.yaml` 中的数据库连接信息,确保与实际数据库匹配。 + +3. **任务调度异常** + - **原因**: Quartz 配置错误或数据库连接问题。 + - **解决方案**: 检查 `application.yaml` 中的 Quartz 配置,确保数据库连接正常。 + +4. **日志记录不完整** + - **原因**: 日志配置文件错误或日志级别设置不当。 + - **解决方案**: 检查 `server-logback.xml` 文件中的配置,确保日志级别和输出格式正确。 + +5. **认证失败** + - **原因**: JWT 密钥错误或超时时间过短。 + - **解决方案**: 检查 `application.yaml` 中的 JWT 配置,确保密钥和超时时间正确。 + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) +- [TokenManager.java](file://datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java) + +## 结论 +DataVines 服务器的配置文档详细说明了所有配置选项,包括服务器端口、线程池配置、日志配置、安全配置(如 JWT、验证码)、跨域配置等。通过 `application.yaml` 配置文件管理各种配置项,确保系统的稳定运行和高效管理。生产环境下的安全配置建议包括使用强密码、合理配置连接池大小、限制允许的源等。配置的加载机制和优先级也得到了明确说明,支持通过环境变量覆盖配置文件中的值。希望本文档能帮助您更好地理解和配置 DataVines 服务器。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/MySQL\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/MySQL\351\205\215\347\275\256.md" new file mode 100644 index 00000000..7d606dd7 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/MySQL\351\205\215\347\275\256.md" @@ -0,0 +1,278 @@ +# MySQL配置 + + +**本文档引用的文件** +- [MysqlParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlParameterConverter.java) +- [JdbcUrlParser.java](file://datavines-common\src\main\java\io\datavines\common\utils\JdbcUrlParser.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [JdbcConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConfigBuilder.java) +- [JdbcParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcParameterConverter.java) +- [ConnectionInfo.java](file://datavines-common\src\main\java\io\datavines\common\entity\ConnectionInfo.java) +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java) +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) + + +## 目录 +1. [简介](#简介) +2. [连接字符串格式](#连接字符串格式) +3. [连接参数配置](#连接参数配置) +4. [SSL配置](#ssl配置) +5. [连接池与性能调优](#连接池与性能调优) +6. [MySQL特有配置](#mysql特有配置) +7. [连接测试](#连接测试) +8. [故障排查](#故障排查) + +## 简介 +本文档详细说明了DataVines平台中MySQL连接器的配置方法。文档涵盖了JDBC连接字符串格式、连接参数配置、SSL设置、连接池参数、性能调优建议以及连接测试方法。通过分析DataVines代码库中的相关实现,提供了MySQL数据库配置的完整指南。 + +**本文档引用的文件** +- [MysqlParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlParameterConverter.java) +- [JdbcUrlParser.java](file://datavines-common\src\main\java\io\datavines\common\utils\JdbcUrlParser.java) + +## 连接字符串格式 +MySQL连接器使用标准的JDBC连接字符串格式,其基本结构如下: + +``` +jdbc:mysql://host:port/database +``` + +其中: +- `host`:MySQL服务器的主机名或IP地址 +- `port`:MySQL服务器的端口号(默认为3306) +- `database`:要连接的数据库名称 + +在DataVines系统中,连接字符串的构建是通过`MysqlParameterConverter`类实现的。该类根据提供的参数动态生成JDBC URL: + +```java +String url = String.format("jdbc:mysql://%s:%s/%s", + parameter.get(HOST), + parameter.get(PORT), + parameter.get(DATABASE)); +``` + +如果需要添加额外的连接参数,可以通过`properties`字段指定,这些参数将以查询字符串的形式附加到URL后面: + +```java +String properties = (String)parameter.get(PROPERTIES); +if (StringUtils.isNotEmpty(properties)) { + url += "?" + properties; +} +``` + +例如,一个完整的连接字符串可能如下所示: +``` +jdbc:mysql://localhost:3306/mydatabase?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true +``` + +**本文档引用的文件** +- [MysqlParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlParameterConverter.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) + +## 连接参数配置 +DataVines平台支持通过参数化配置来设置MySQL连接的各种选项。这些参数主要通过`JdbcConfigBuilder`和`JdbcParameterConverter`类进行处理。 + +### 基本连接参数 +以下是MySQL连接器支持的基本参数: + +| 参数 | 说明 | 是否必需 | +|------|------|---------| +| host | 数据库服务器地址 | 是 | +| port | 数据库服务器端口 | 是 | +| database | 要连接的数据库名称 | 是 | +| user | 数据库用户名 | 是 | +| password | 数据库密码 | 否 | +| properties | 额外的连接属性 | 否 | + +这些参数在`JdbcConfigBuilder`类中定义,通过`getHostInput`、`getPortInput`、`getDatabaseInput`等方法创建相应的输入字段。 + +### 连接属性 +通过`properties`参数可以传递额外的JDBC连接属性,这些属性以`key=value&key1=value1`的格式指定。常见的MySQL连接属性包括: + +- `useSSL`:是否启用SSL连接 +- `serverTimezone`:服务器时区设置 +- `allowPublicKeyRetrieval`:是否允许公钥检索 +- `connectTimeout`:连接超时时间(毫秒) +- `socketTimeout`:套接字超时时间(毫秒) +- `autoReconnect`:是否自动重连 +- `maxReconnects`:最大重连次数 +- `initialTimeout`:初始重连延迟(秒) + +在DataVines中,这些属性可以通过UI界面或API调用进行配置,最终会被附加到JDBC URL的查询字符串部分。 + +**本文档引用的文件** +- [JdbcConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConfigBuilder.java) +- [JdbcParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcParameterConverter.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) + +## SSL配置 +DataVines平台支持MySQL的SSL连接配置,以确保数据库通信的安全性。SSL配置主要通过连接属性来实现。 + +### SSL连接参数 +要启用SSL连接,需要在连接属性中设置相应的参数: + +```properties +useSSL=true&requireSSL=true&verifyServerCertificate=true +``` + +- `useSSL=true`:启用SSL连接 +- `requireSSL=true`:要求使用SSL连接 +- `verifyServerCertificate=true`:验证服务器证书 + +### 自定义信任库 +如果需要使用自定义的信任库,可以添加以下参数: + +```properties +trustCertificateKeyStoreUrl=file:/path/to/truststore&trustCertificateKeyStorePassword=password +``` + +在DataVines的代码实现中,SSL配置是通过`properties`参数传递的,系统会将其直接附加到JDBC连接字符串中。对于需要更复杂SSL配置的场景,可以通过扩展`MysqlParameterConverter`类来实现自定义的SSL配置逻辑。 + +**本文档引用的文件** +- [MysqlParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlParameterConverter.java) +- [JdbcUrlParser.java](file://datavines-common\src\main\java\io\datavines\common\utils\JdbcUrlParser.java) + +## 连接池与性能调优 +DataVines平台通过连接池管理来优化MySQL连接的性能和资源利用率。 + +### 连接复用 +系统通过`JdbcExecutorClientManager`类实现连接的复用和管理: + +```java +private final ConcurrentHashMap clientMap = new ConcurrentHashMap<>(); +``` + +该类使用单例模式,通过ConcurrentHashMap存储和管理JDBC连接客户端,确保连接的高效复用。 + +### 批量操作优化 +对于批量数据操作,建议使用以下配置来优化性能: + +- `rewriteBatchedStatements=true`:启用批处理语句重写 +- `useServerPrepStmts=true`:使用服务器端预处理语句 +- `cachePrepStmts=true`:缓存预处理语句 +- `prepStmtCacheSize=250`:预处理语句缓存大小 +- `prepStmtCacheSqlLimit=2048`:预处理语句SQL长度限制 + +### 查询超时设置 +为了防止长时间运行的查询影响系统性能,建议设置查询超时: + +```properties +socketTimeout=30000&connectTimeout=10000 +``` + +- `socketTimeout`:设置套接字读取超时时间 +- `connectTimeout`:设置连接超时时间 + +这些超时设置可以有效防止查询阻塞,提高系统的稳定性和响应性。 + +**本文档引用的文件** +- [JdbcExecutorClientManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcExecutorClientManager.java) +- [MysqlParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-mysql\src\main\java\io\datavines\connector\plugin\MysqlParameterConverter.java) + +## MySQL特有配置 +DataVines平台针对MySQL数据库提供了一些特有的配置选项和功能。 + +### 故障转移配置 +DataVines使用MySQL作为注册中心时,实现了基于MySQL的故障转移机制。通过`MysqlMutex`和`MysqlServerStateManager`类实现分布式锁和服务器状态管理: + +```java +public class MysqlMutex { + private Connection connection; + private final Properties properties; + private final ServerInfo serverInfo; + private final ConcurrentHashMap lockHoldMap; +} +``` + +这种机制确保了在多节点部署时的高可用性和故障转移能力。 + +### 读写分离 +虽然DataVines本身没有直接实现读写分离,但可以通过配置多个数据源来实现读写分离: + +- 主数据源:用于写操作 +- 从数据源:用于读操作 + +通过在应用程序层面路由读写请求到不同的数据源,可以实现基本的读写分离功能。 + +### 批量插入优化 +对于批量插入操作,建议使用以下优化配置: + +```properties +rewriteBatchedStatements=true&useServerPrepStmts=true&cachePrepStmts=true +``` + +这些配置可以显著提高批量插入的性能,特别是在处理大量数据时。 + +**本文档引用的文件** +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java) +- [MysqlServerStateManager.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlServerStateManager.java) +- [MysqlRegistry.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlRegistry.java) + +## 连接测试 +DataVines平台提供了多种方式来测试MySQL连接的连通性和性能。 + +### 连通性测试 +系统通过`JdbcUrlParser`类解析和验证连接信息: + +```java +public static ConnectionInfo getConnectionInfo(String jdbcUrl, String username, String password) { + // 解析JDBC URL并返回连接信息 +} +``` + +该方法可以验证连接字符串的正确性,并提取出主机、端口、数据库等基本信息。 + +### 性能测试 +为了测试连接性能,建议使用以下方法: + +1. **连接建立时间**:测量从发起连接到成功建立连接的时间 +2. **查询响应时间**:执行简单的查询语句(如`SELECT 1`)并测量响应时间 +3. **并发连接测试**:测试系统在高并发情况下的连接性能 + +在DataVines中,这些测试可以通过调用相应的API接口或使用内置的测试工具来完成。 + +### 健康检查 +系统定期执行健康检查来确保MySQL连接的可用性: + +```java +public boolean acquire(String lockKey, long timeout){ + return registry.acquire(key, timeout); +} +``` + +通过尝试获取分布式锁来验证连接的活跃状态,确保系统能够及时发现和处理连接问题。 + +**本文档引用的文件** +- [JdbcUrlParser.java](file://datavines-common\src\main\java\io\datavines\common\utils\JdbcUrlParser.java) +- [ConnectionInfo.java](file://datavines-common\src\main\java\io\datavines\common\entity\ConnectionInfo.java) + +## 故障排查 +当MySQL连接出现问题时,可以参考以下排查步骤: + +### 常见问题及解决方案 +1. **连接超时** + - 检查网络连接是否正常 + - 验证主机名和端口是否正确 + - 检查防火墙设置 + +2. **认证失败** + - 确认用户名和密码是否正确 + - 检查用户是否有连接数据库的权限 + - 验证数据库是否允许远程连接 + +3. **SSL连接问题** + - 确认服务器证书是否有效 + - 检查SSL配置参数是否正确 + - 验证信任库设置 + +### 日志分析 +查看系统日志中的错误信息,重点关注以下内容: +- 连接建立失败的详细错误信息 +- SSL握手失败的原因 +- 连接池耗尽的警告 + +通过分析日志可以快速定位问题根源,并采取相应的解决措施。 + +**本文档引用的文件** +- [JdbcUrlParser.java](file://datavines-common\src\main\java\io\datavines\common\utils\JdbcUrlParser.java) +- [MysqlMutex.java](file://datavines-registry\datavines-registry-plugins\datavines-registry-mysql\src\main\java\io\datavines\registry\plugin\MysqlMutex.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/Oracle\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/Oracle\351\205\215\347\275\256.md" new file mode 100644 index 00000000..d74e752f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/Oracle\351\205\215\347\275\256.md" @@ -0,0 +1,159 @@ +# Oracle配置 + + +**本文档引用的文件** +- [OracleConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleConfigBuilder.java) +- [OracleDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleDataSourceInfo.java) +- [OracleParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleParameterConverter.java) +- [OracleDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleDialect.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) +- [JdbcConnectionInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcConnectionInfo.java) +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java) + + +## 目录 +1. [JDBC连接字符串格式](#jdbc连接字符串格式) +2. [连接参数配置](#连接参数配置) +3. [SSL配置方法](#ssl配置方法) +4. [连接池参数设置](#连接池参数设置) +5. [Oracle特有配置选项](#oracle特有配置选项) +6. [性能调优建议](#性能调优建议) +7. [连接测试方法](#连接测试方法) + +## JDBC连接字符串格式 + +Oracle连接器支持标准的JDBC连接字符串格式,采用Oracle Thin驱动程序进行连接。连接字符串的格式遵循Oracle官方规范,主要支持两种格式: + +1. **服务名格式**:`jdbc:oracle:thin:@//host:port/service_name` +2. **SID格式**:`jdbc:oracle:thin:@host:port:SID` + +在DataVines实现中,Oracle连接器使用服务名格式作为默认连接方式。连接字符串的构建通过`OracleParameterConverter`类的`getUrl`方法实现,该方法根据提供的主机、端口和SID参数生成完整的JDBC URL。 + +连接字符串的地址部分由`OracleDataSourceInfo`类的`getAddress`方法生成,格式为`jdbc:oracle:thin:@//host:port`。完整的JDBC URL通过`getJdbcUrl`方法构建,该方法在地址基础上附加SID和服务名。 + +**Section sources** +- [OracleParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleParameterConverter.java#L29-L38) +- [OracleDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleDataSourceInfo.java#L34-L35) + +## 连接参数配置 + +Oracle连接器的配置参数通过`OracleConfigBuilder`类定义,该类继承自`JdbcConfigBuilder`并添加了Oracle特有的配置项。主要连接参数包括: + +- **主机地址**(host):数据库服务器的IP地址或主机名 +- **端口**(port):数据库监听端口,默认为1521 +- **SID**(sid):Oracle系统标识符 +- **用户名**(user):数据库连接用户名 +- **密码**(password):数据库连接密码 +- **附加属性**(properties):其他连接参数,以key=value&key1=value1格式提供 + +`OracleConfigBuilder`类的`build`方法负责生成配置参数的JSON表示,该方法定义了配置界面中显示的参数列表。SID参数通过`getSID`方法单独定义,该参数是必填项。 + +附加属性参数允许用户指定Oracle JDBC驱动的特定连接属性,这些属性将附加到JDBC URL的查询字符串部分。`BaseJdbcDataSourceInfo`类的`appendProperties`方法负责处理这些附加属性。 + +**Section sources** +- [OracleConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleConfigBuilder.java#L34-L63) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L135-L139) + +## SSL配置方法 + +虽然代码库中没有直接显示Oracle SSL配置的具体实现,但可以通过连接参数中的附加属性来配置SSL连接。Oracle JDBC驱动支持通过连接属性配置SSL/TLS加密。 + +SSL配置通常通过在连接字符串的附加属性中指定以下参数来实现: + +- `oracle.net.ssl_server_dn_match`:启用服务器DN匹配验证 +- `oracle.net.ssl_version`:指定SSL/TLS版本 +- `javax.net.ssl.trustStore`:指定信任库路径 +- `javax.net.ssl.trustStorePassword`:指定信任库密码 + +这些SSL相关参数可以通过`properties`字段以key=value格式提供,并与其他连接参数用&符号分隔。`OracleParameterConverter`类的`getUrl`方法会将这些附加属性附加到JDBC URL的查询字符串部分。 + +**Section sources** +- [OracleParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleParameterConverter.java#L34-L36) + +## 连接池参数设置 + +DataVines使用HikariCP作为数据库连接池实现,连接池的配置在`JdbcDataSourceManager`类中定义。虽然Oracle连接器本身不直接管理连接池参数,但系统级的连接池配置会影响所有数据库连接,包括Oracle。 + +连接池的主要参数包括: + +- **最大连接池大小**:通过`setMaximumPoolSize`方法设置,默认值为10 +- **驱动类名**:通过`setDriverClassName`方法设置,Oracle为`oracle.jdbc.driver.OracleDriver` +- **JDBC URL**:从数据源信息中获取 +- **用户名和密码**:从数据源信息中获取 + +`JdbcDataSourceManager`类的`getDataSource`方法负责创建和管理连接池。当请求新的数据源连接时,该方法会检查是否存在已缓存的连接池,如果不存在则创建新的HikariDataSource实例。 + +连接池的配置是全局的,适用于所有使用JDBC连接的数据库类型。连接池实例通过数据源的唯一键(由`getUniqueKey`方法生成)进行缓存和管理。 + +**Section sources** +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java#L59-L88) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L166-L168) + +## Oracle特有配置选项 + +### 服务名与SID的区别 + +在Oracle数据库中,服务名(Service Name)和SID(System Identifier)是两种不同的数据库标识方式: + +- **SID**:是数据库实例的唯一标识符,通常在数据库创建时指定 +- **服务名**:是数据库服务的逻辑名称,可以由一个或多个实例提供服务 + +在DataVines的Oracle连接器中,SID作为主要的连接标识符。`OracleDataSourceInfo`类的`appendSid`方法负责将SID附加到JDBC URL中。如果SID参数不为空,则将其附加到地址后面。 + +### TNS配置 + +代码库中没有直接支持TNS(Transparent Network Substrate)配置。连接主要通过直接的主机、端口和SID/服务名进行,而不是使用TNS别名。这简化了配置过程,但限制了使用复杂的TNS网络配置。 + +### Oracle RAC配置 + +对于Oracle RAC(Real Application Clusters)环境,可以通过在主机参数中指定多个地址来实现连接。虽然代码中没有专门的RAC配置,但Oracle JDBC驱动本身支持RAC连接。 + +RAC连接可以通过在连接字符串中使用地址列表来实现,例如: +`jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=host1)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=host2)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=service_name)))` + +然而,当前的`OracleDataSourceInfo`实现主要支持简单的单主机连接格式。 + +**Section sources** +- [OracleDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleDataSourceInfo.java#L68-L75) + +## 性能调优建议 + +### 连接复用 + +DataVines通过连接池实现连接复用,避免了频繁创建和销毁数据库连接的开销。`JdbcDataSourceManager`类维护一个连接池缓存,通过数据源的唯一键来识别和重用现有的连接池。 + +连接复用的实现基于`getUniqueKey`方法生成的MD5哈希值,该值由主机、端口、数据库、用户名等参数组合生成。相同的连接参数将使用同一个连接池实例。 + +### 批量操作 + +虽然代码中没有直接显示批量操作的配置,但可以通过JDBC的批量处理功能来优化大量数据的插入和更新操作。建议在执行大量数据操作时使用PreparedStatement的addBatch和executeBatch方法。 + +### 查询超时设置 + +查询超时可以通过JDBC连接的`setQueryTimeout`方法设置。虽然在提供的代码中没有直接显示超时设置,但可以在执行查询时通过JdbcTemplate或类似的工具类来配置查询超时。 + +Oracle JDBC驱动支持以下超时相关参数: +- `oracle.jdbc.ReadTimeout`:读取超时(毫秒) +- `oracle.net.CONNECT_TIMEOUT`:连接超时(毫秒) + +这些参数可以通过连接字符串的附加属性进行配置。 + +**Section sources** +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java#L71-L92) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L166-L168) + +## 连接测试方法 + +Oracle连接器的连通性测试通过`OracleDataSourceInfo`类的`getConnection`方法实现。该方法使用标准的JDBC流程来测试连接: + +1. 加载Oracle JDBC驱动类 +2. 使用JDBC URL、用户名和密码创建数据库连接 +3. 返回连接对象或抛出异常 + +连接测试的验证查询由`getValidationQuery`方法定义,对于Oracle数据库,使用`Select 1 FROM DUAL`作为验证查询。DUAL是Oracle中的一个特殊单行表,常用于测试连接和执行函数。 + +`BaseJdbcDataSourceInfo`类的`getConnection`方法提供了通用的连接测试逻辑,该方法被所有JDBC数据源类型继承和使用。连接测试过程中会加载驱动类并尝试建立实际的数据库连接。 + +**Section sources** +- [OracleDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-oracle\src\main\java\io\datavines\connector\plugin\OracleDataSourceInfo.java#L53-L55) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L149-L152) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/PostgreSQL\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/PostgreSQL\351\205\215\347\275\256.md" new file mode 100644 index 00000000..dc8a742c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/PostgreSQL\351\205\215\347\275\256.md" @@ -0,0 +1,434 @@ +# PostgreSQL配置 + + +**本文档引用的文件** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlDataSourceInfo.java) +- [PostgreSqlConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlConnector.java) +- [PostgreSqlConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlConfigBuilder.java) +- [PostgreSqlTypeConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlTypeConverter.java) +- [PostgreSqlParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlParameterConverter.java) +- [JdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) +- [JdbcConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConfigBuilder.java) +- [JdbcUrlParser.java](file://datavines-common\src\main\java\io\datavines\common\utils\JdbcUrlParser.java) + + +## 目录 +1. [JDBC连接字符串格式](#jdbc连接字符串格式) +2. [连接参数配置](#连接参数配置) +3. [SSL配置方法](#ssl配置方法) +4. [连接池参数设置](#连接池参数设置) +5. [PostgreSQL特有配置选项](#postgresql特有配置选项) +6. [性能调优建议](#性能调优建议) +7. [连接器连通性和性能测试](#连接器连通性和性能测试) + +## JDBC连接字符串格式 + +PostgreSQL连接器的JDBC连接字符串遵循标准格式,由协议、主机、端口和数据库名称组成。根据代码实现,PostgreSQL连接器的地址格式为: + +``` +jdbc:postgresql://host:port/database +``` + +其中: +- `jdbc:postgresql://` 是PostgreSQL的JDBC协议前缀 +- `host` 是数据库服务器的主机名或IP地址 +- `port` 是数据库服务器的端口号(默认为5432) +- `database` 是要连接的数据库名称 + +在代码中,`PostgreSqlDataSourceInfo`类的`getAddress()`方法实现了这一格式的构建: + +```java +@Override +public String getAddress() { + return "jdbc:postgresql://"+getHost()+":"+getPort(); +} +``` + +完整的JDBC URL通过`getJdbcUrl()`方法构建,该方法在基类`BaseJdbcDataSourceInfo`中实现,将地址、数据库名称和连接参数组合在一起。 + +**本节来源** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlDataSourceInfo.java#L34-L37) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L96-L103) + +## 连接参数配置 + +PostgreSQL连接器支持多种连接参数,这些参数可以通过URL查询字符串的形式附加到JDBC连接字符串后面。参数之间使用`&`符号分隔。 + +### 基本连接参数 + +根据`JdbcConfigBuilder`和`PostgreSqlConfigBuilder`类的实现,PostgreSQL连接器需要以下基本参数: + +- **host**: 数据库服务器地址 +- **port**: 数据库服务器端口 +- **database**: 要连接的数据库名称 +- **schema**: 模式名称(PostgreSQL特有,必填) +- **user**: 用户名 +- **password**: 密码 +- **properties**: 其他连接属性,格式为`key=value&key1=value1` + +PostgreSQL连接器特别要求模式(schema)参数是必需的,这在`PostgreSqlConfigBuilder`类中通过设置验证规则实现: + +```java +@Override +protected InputParam getSchemaInput(boolean isEn) { + return getInputParam("schema", + isEn ? "schema" : "模式", + isEn ? "please enter schema" : "请填入模式", 1, + Validate.newBuilder().setRequired(true).setMessage(isEn ? "please enter schema" : "请填入模式").build(), null); +} +``` + +### 连接参数处理 + +连接参数通过`filterProperties`方法进行处理,该方法会过滤掉敏感参数`autoDeserialize=true`,以防止潜在的安全风险: + +```java +@Override +protected String filterProperties(String other){ + if(StringUtils.isBlank(other)){ + return ""; + } + + String sensitiveParam = "autoDeserialize=true"; + if(other.contains(sensitiveParam)){ + int index = other.indexOf(sensitiveParam); + String tmp = sensitiveParam; + char symbol = '&'; + if(index == 0 || other.charAt(index + 1) == symbol){ + tmp = tmp + symbol; + } else if(other.charAt(index - 1) == symbol){ + tmp = symbol + tmp; + } + logger.warn("sensitive param : {} in properties field is filtered", tmp); + other = other.replace(tmp, ""); + } + logger.debug("properties : {}", other); + return other; +} +``` + +**本节来源** +- [PostgreSqlConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlConfigBuilder.java#L24-L30) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlDataSourceInfo.java#L55-L75) +- [JdbcConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConfigBuilder.java#L77-L129) + +## SSL配置方法 + +虽然在提供的代码片段中没有直接显示SSL配置的具体实现,但PostgreSQL JDBC驱动支持多种SSL连接模式。可以通过在连接参数中添加SSL相关属性来配置SSL连接。 + +### SSL连接参数 + +PostgreSQL JDBC驱动支持以下SSL相关参数: + +- **ssl**: 是否启用SSL连接(true/false) +- **sslmode**: SSL模式,可选值包括: + - `disable`: 禁用SSL + - `allow`: 首先尝试非SSL连接,如果失败则尝试SSL + - `prefer`(默认): 首先尝试SSL连接,如果失败则尝试非SSL + - `require`: 必须使用SSL连接,不验证服务器证书 + - `verify-ca`: 必须使用SSL连接,并验证服务器证书是否由受信任的CA签发 + - `verify-full`: 必须使用SSL连接,并验证服务器证书是否由受信任的CA签发,且主机名与证书中的主机名匹配 + +- **sslcert**: 客户端证书文件路径 +- **sslkey**: 客户端密钥文件路径 +- **sslrootcert**: 信任的CA证书文件路径 +- **sslfactory**: SSL工厂类 + +### 配置示例 + +在连接参数中配置SSL连接: + +``` +ssl=true&sslmode=require&sslcert=/path/to/client-cert.pem&sslkey=/path/to/client-key.pem&sslrootcert=/path/to/ca-cert.pem +``` + +由于PostgreSQL连接器的`filterProperties`方法会过滤掉包含`autoDeserialize=true`的参数,建议在配置SSL时避免使用可能触发安全过滤的参数。 + +**本节来源** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlDataSourceInfo.java#L55-L75) + +## 连接池参数设置 + +在提供的代码库中,没有直接显示连接池的具体配置,但可以通过JDBC连接参数来配置连接池行为。PostgreSQL JDBC驱动本身不提供连接池功能,但可以与第三方连接池库(如HikariCP、Apache DBCP等)集成。 + +### 连接池相关参数 + +虽然连接池通常由外部库管理,但可以通过JDBC参数影响连接行为: + +- **loginTimeout**: 连接超时时间(秒) +- **socketTimeout**: Socket操作超时时间(秒) +- **connectTimeout**: 连接建立超时时间(秒) +- **cancelSignalTimeout**: 取消信号超时时间(秒) + +### 连接验证 + +PostgreSQL连接器使用自定义的验证查询来测试连接: + +```java +@Override +public String getValidationQuery() { + return "SELECT 'x'"; +} +``` + +这与许多数据库使用的`SELECT 1`不同,使用字符串`'x'`作为验证查询。这个查询非常轻量,适合用于连接池的连接验证。 + +### 连接管理 + +在`JdbcConnector`类中,连接的获取和释放通过`dataSourceClient`完成: + +```java +protected Connection getConnection(String dataSourceParam, Map param) throws SQLException { + return dataSourceClient.getConnection(JdbcDataSourceInfoManager.getDatasourceInfo(dataSourceParam, getDatasourceInfo(param))); +} +``` + +连接在使用后会被正确释放: + +```java +JdbcDataSourceUtils.releaseConnection(connection); +``` + +**本节来源** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlDataSourceInfo.java#L78-L80) +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java#L62-L64) +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java#L83-L84) + +## PostgreSQL特有配置选项 + +PostgreSQL连接器实现了一些特定于PostgreSQL的配置和功能。 + +### 模式搜索路径配置 + +PostgreSQL使用模式(schema)作为数据库对象的命名空间。在`PostgreSqlConfigBuilder`中,模式被设置为必填参数,这反映了PostgreSQL对模式的重视: + +```java +@Override +protected InputParam getSchemaInput(boolean isEn) { + return getInputParam("schema", + isEn ? "schema" : "模式", + isEn ? "please enter schema" : "请填入模式", 1, + Validate.newBuilder().setRequired(true).setMessage(isEn ? "please enter schema" : "请填入模式").build(), null); +} +``` + +在连接时,模式信息被用于元数据查询。当获取表列表时,会使用指定的模式: + +```java +String catalog; +String schema; + +if (StringUtils.isNotEmpty(paramMap.get(CATALOG))) { + catalog = paramMap.get(CATALOG); + schema = param.getDatabase(); +} else { + catalog = param.getDatabase(); + schema = StringUtils.isEmptyOrNullStr(paramMap.get(SCHEMA)) ? null : paramMap.get(SCHEMA); +} +``` + +### 数据类型处理 + +`PostgreSqlTypeConverter`类负责将PostgreSQL的原生数据类型转换为系统内部的数据类型。PostgreSQL支持丰富的数据类型,包括一些特有的类型: + +```java +@Override +public DataType convert(String originType) { + if (StringUtils.isEmpty(originType)) { + throw new UnsupportedOperationException("sql type id null error"); + } + switch (originType.toUpperCase()) { + case "INT4": + case "INT2": + case "OID": + case "SERIAL": + return DataType.INT_TYPE; + case "BIGSERIAL": + case "INT8": + return DataType.LONG_TYPE; + case "BOOL": + return DataType.BOOLEAN_TYPE; + case "FLOAT8": + case "FLOAT4": + case "REAL": + return DataType.FLOAT_TYPE; + case "NUMBER": + case "MONEY": + return DataType.DOUBLE_TYPE; + case "TIMESTAMPTZ": + return DataType.TIMESTAMP_TYPE; + case "TIMETZ": + return DataType.TIME_TYPE; + case "BPCHAR": + case "UUID": + case "JSONB": + case "XML": + return DataType.STRING_TYPE; + case "NUMERIC": + return DataType.BIG_DECIMAL_TYPE; + case "CIDR": + case "INET": + case "JSONPATH": + case "CIRCLE": + case "POINT": + case "LINE": + case "BOX": + case "PATH": + case "POLYGON": + case "LSEG": + case "VARBIT": + return DataType.OBJECT; + default: + return super.convert(originType); + } +} +``` + +特别值得注意的是: +- `JSONB` 和 `JSONPATH` 类型被映射为字符串类型 +- `UUID`、`CIDR`、`INET` 等网络相关类型被映射为字符串类型 +- 几何类型(`POINT`、`LINE`、`BOX`、`PATH`、`POLYGON`、`CIRCLE`)被映射为对象类型 +- `VARBIT`(可变长度位串)被映射为对象类型 + +### 数组类型处理 + +虽然在提供的代码中没有直接显示数组类型的处理,但PostgreSQL的JDBC驱动原生支持数组类型。可以通过标准的JDBC API来处理数组: + +```java +// 获取数组 +Array array = resultSet.getArray("array_column"); +Object[] values = (Object[]) array.getArray(); + +// 设置数组参数 +Connection connection = dataSource.getConnection(); +java.sql.Array sqlArray = connection.createArrayOf("text", new String[]{"a", "b", "c"}); +preparedStatement.setArray(1, sqlArray); +``` + +### JSON类型支持 + +PostgreSQL的`JSONB`类型被映射为字符串类型,这意味着JSON数据在系统中作为字符串处理。对于需要JSON处理的场景,可以在应用层进行JSON解析和操作。 + +**本节来源** +- [PostgreSqlConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlConfigBuilder.java#L24-L30) +- [PostgreSqlTypeConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlTypeConverter.java#L24-L71) +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java#L113-L119) + +## 性能调优建议 + +基于代码实现和PostgreSQL最佳实践,以下是性能调优建议。 + +### 连接复用 + +连接复用是提高性能的关键。系统通过`dataSourceClient`管理连接,确保连接可以被复用: + +```java +protected Connection getConnection(String dataSourceParam, Map param) throws SQLException { + return dataSourceClient.getConnection(JdbcDataSourceInfoManager.getDatasourceInfo(dataSourceParam, getDatasourceInfo(param))); +} +``` + +建议: +- 使用连接池来管理数据库连接 +- 设置合理的连接池大小,避免过多的连接导致数据库资源耗尽 +- 配置连接池的最小和最大连接数,根据应用负载进行调整 + +### 批量操作 + +对于大量数据的插入或更新操作,使用批量操作可以显著提高性能: + +```java +// 批量插入示例 +PreparedStatement pstmt = connection.prepareStatement("INSERT INTO table (col1, col2) VALUES (?, ?)"); +for (Data data : dataList) { + pstmt.setString(1, data.getCol1()); + pstmt.setString(2, data.getCol2()); + pstmt.addBatch(); +} +pstmt.executeBatch(); +``` + +### 查询超时设置 + +设置查询超时可以防止长时间运行的查询影响系统性能: + +```java +// 设置查询超时 +statement.setQueryTimeout(30); // 30秒超时 +``` + +或者通过连接参数设置: + +``` +socketTimeout=30&connectTimeout=10 +``` + +### 其他性能优化 + +1. **使用PreparedStatement**: 对于重复执行的SQL语句,使用PreparedStatement可以提高性能并防止SQL注入。 + +2. **合理使用索引**: 确保查询中使用的列有适当的索引。 + +3. **避免SELECT ***: 只选择需要的列,减少数据传输量。 + +4. **使用合适的事务隔离级别**: 根据业务需求选择合适的隔离级别,避免不必要的锁竞争。 + +5. **监控和分析慢查询**: 使用PostgreSQL的`pg_stat_statements`扩展来监控和分析慢查询。 + +**本节来源** +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java#L62-L64) + +## 连接器连通性和性能测试 + +系统提供了测试连接的功能,可以通过`testConnect`方法来验证连接器的连通性。 + +### 连通性测试 + +`testConnect`方法实现了连接测试功能: + +```java +@Override +public ConnectorResponse testConnect(TestConnectionRequestParam param) { + Map paramMap = JSONUtils.toMap(param.getDataSourceParam()); + BaseJdbcDataSourceInfo dataSourceInfo = getDatasourceInfo(paramMap); + dataSourceInfo.loadClass(); + + try (Connection con = DriverManager.getConnection(dataSourceInfo.getJdbcUrl(), dataSourceInfo.getUser(), dataSourceInfo.getPassword())) { + boolean result = con != null; + if (result) { + con.close(); + } + return ConnectorResponse.builder().status(ConnectorResponse.Status.SUCCESS).result(result).build(); + } catch (SQLException e) { + logger.error("test connect error, param is {} :", JSONUtils.toJsonString(param), e); + } + + return ConnectorResponse.builder().status(ConnectorResponse.Status.SUCCESS).result(false).build(); +} +``` + +测试过程包括: +1. 解析连接参数 +2. 加载JDBC驱动类 +3. 尝试建立数据库连接 +4. 如果连接成功,立即关闭连接 +5. 返回测试结果 + +### 性能测试 + +虽然没有直接的性能测试方法,但可以通过以下方式评估连接器性能: + +1. **连接建立时间**: 测量`getConnection`方法的执行时间。 +2. **查询响应时间**: 测量执行查询的响应时间。 +3. **并发性能**: 测试多线程并发访问时的性能表现。 + +### 测试建议 + +1. **连接测试**: 在配置新的数据源后,首先使用测试连接功能验证配置是否正确。 +2. **超时测试**: 验证连接超时和查询超时设置是否生效。 +3. **SSL连接测试**: 如果配置了SSL,确保SSL连接能够正常建立。 +4. **长时间运行测试**: 进行长时间运行测试,确保连接不会意外断开。 + +**本节来源** +- [JdbcConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConnector.java#L196-L212) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-postgresql\src\main\java\io\datavines\connector\plugin\PostgreSqlDataSourceInfo.java#L149-L152) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/SQL Server\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/SQL Server\351\205\215\347\275\256.md" new file mode 100644 index 00000000..0ffbdcfd --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/SQL Server\351\205\215\347\275\256.md" @@ -0,0 +1,336 @@ +# SQL Server配置 + + +**本文档引用的文件** +- [SqlServerDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerDataSourceInfo.java) +- [SqlServerParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerParameterConverter.java) +- [SqlServerConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerConfigBuilder.java) +- [SqlServerConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerConnector.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java) +- [JdbcConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConfigBuilder.java) + + +## 目录 +1. [简介](#简介) +2. [JDBC连接字符串格式](#jdbc连接字符串格式) +3. [连接参数配置](#连接参数配置) +4. [SSL配置方法](#ssl配置方法) +5. [连接池参数设置](#连接池参数设置) +6. [SQL Server特有配置选项](#sql-server特有配置选项) +7. [性能调优建议](#性能调优建议) +8. [连接器连通性和性能测试](#连接器连通性和性能测试) + +## 简介 +本文档详细说明了DataVines平台中SQL Server连接器的配置方法。文档涵盖了JDBC连接字符串格式、连接参数、SSL配置、连接池设置、SQL Server特有配置选项、性能调优建议以及连接器连通性和性能测试方法。 + +**本文档引用的文件** +- [SqlServerDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerDataSourceInfo.java) +- [SqlServerParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerParameterConverter.java) + +## JDBC连接字符串格式 +SQL Server连接器使用标准的JDBC连接字符串格式,其基本结构如下: + +``` +jdbc:sqlserver://host:port;databaseName=database +``` + +在DataVines平台中,该连接字符串由`SqlServerDataSourceInfo`类动态生成。连接字符串的构建过程如下: + +1. 基础地址格式为`jdbc:sqlserver://host:port` +2. 数据库名称通过`databaseName`参数指定 +3. 其他连接属性通过分号(`;`)分隔添加 + +```mermaid +flowchart TD +Start["开始构建JDBC URL"] --> GetAddress["获取基础地址
jdbc:sqlserver://host:port"] +GetAddress --> CheckSeparator["检查地址末尾是否已有分号"] +CheckSeparator --> |无分号| AppendDatabaseName["添加;databaseName="] +CheckSeparator --> |有分号| SkipAppend["跳过添加"] +AppendDatabaseName --> AddDatabase["添加数据库名称"] +SkipAppend --> AddDatabase +AddDatabase --> AddProperties["添加其他属性"] +AddProperties --> ReturnURL["返回完整的JDBC URL"] +ReturnURL --> End["结束"] +``` + +**图源** +- [SqlServerDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerDataSourceInfo.java#L53-L64) + +**本节源码** +- [SqlServerDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerDataSourceInfo.java#L53-L64) + +## 连接参数配置 +SQL Server连接器支持多种连接参数配置,这些参数通过`SqlServerParameterConverter`类进行处理。 + +### 基本连接参数 +基本连接参数包括: +- **host**: SQL Server服务器地址 +- **port**: SQL Server端口号(默认1433) +- **database**: 要连接的数据库名称 +- **user**: 用户名 +- **password**: 密码 + +### 高级连接参数 +高级连接参数通过`properties`字段配置,以键值对形式提供,多个参数用分号分隔。 + +```mermaid +classDiagram +class SqlServerParameterConverter { ++getUrl(Map parameter) String +} +class JdbcParameterConverter { ++getUrl(Map parameter) String +} +SqlServerParameterConverter --> JdbcParameterConverter : "继承" +``` + +**图源** +- [SqlServerParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerParameterConverter.java#L27-L38) + +**本节源码** +- [SqlServerParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerParameterConverter.java#L27-L38) + +## SSL配置方法 +SQL Server连接器支持SSL加密连接,通过配置特定参数实现。 + +### SSL相关参数 +主要SSL配置参数包括: +- **encrypt**: 是否启用加密连接 + - true: 启用SSL加密 + - false: 禁用SSL加密 +- **trustServerCertificate**: 是否信任服务器证书 + - true: 不验证服务器证书 + - false: 验证服务器证书(默认值) + +在DataVines平台中,`trustServerCertificate`参数的默认值设置为`false`,确保连接安全性。 + +```mermaid +sequenceDiagram +participant User as "用户" +participant ConfigBuilder as "配置构建器" +participant ParameterConverter as "参数转换器" +participant SQLServer as "SQL Server" +User->>ConfigBuilder : 输入连接配置 +ConfigBuilder->>ConfigBuilder : 设置默认参数 +ConfigBuilder->>ParameterConverter : 生成连接参数 +ParameterConverter->>ParameterConverter : 构建JDBC URL +ParameterConverter->>SQLServer : 建立SSL连接 +alt SSL启用 +SQLServer-->>ParameterConverter : SSL握手 +ParameterConverter-->>ConfigBuilder : 连接成功 +else SSL禁用 +SQLServer-->>ParameterConverter : 明文连接 +ParameterConverter-->>ConfigBuilder : 连接成功 +end +ConfigBuilder-->>User : 返回连接结果 +``` + +**图源** +- [SqlServerConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerConfigBuilder.java#L26-L30) + +**本节源码** +- [SqlServerConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-sqlserver\src\main\java\io\datavines\connector\plugin\SqlServerConfigBuilder.java#L26-L30) + +## 连接池参数设置 +DataVines平台使用HikariCP作为连接池实现,为SQL Server连接器提供高效的连接管理。 + +### 连接池配置 +连接池的主要配置参数: +- **最大连接数**: 10个连接 +- **连接超时**: 默认值 +- **空闲超时**: 默认值 +- **生命周期超时**: 默认值 + +连接池由`JdbcDataSourceManager`类管理,确保连接的高效复用和资源优化。 + +```mermaid +classDiagram +class JdbcDataSourceManager { +-ConcurrentHashMap dataSourceMap ++getDataSource(BaseJdbcDataSourceInfo) DataSource ++getDataSource(Map) DataSource ++getDataSource(Properties) DataSource ++close() void +} +class BaseJdbcDataSourceInfo { ++getJdbcUrl() String ++getDriverClass() String ++getUser() String ++getPassword() String +} +class HikariConfig { ++setJdbcUrl(String) ++setUsername(String) ++setPassword(String) ++setDriverClassName(String) ++setMaximumPoolSize(int) +} +JdbcDataSourceManager --> HikariConfig : "创建配置" +JdbcDataSourceManager --> BaseJdbcDataSourceInfo : "获取连接信息" +HikariConfig --> HikariDataSource : "创建数据源" +``` + +**图源** +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java#L55-L63) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L96-L103) + +**本节源码** +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java#L55-L63) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L96-L103) + +## SQL Server特有配置选项 +SQL Server连接器支持多种特有配置选项,以满足不同的部署需求。 + +### Windows身份验证配置 +虽然当前代码中未直接实现Windows身份验证,但平台架构支持通过Kerberos认证进行集成Windows身份验证。 + +相关配置参数: +- **keytabFile**: Kerberos keytab文件路径 +- **keytabPrincipal**: Kerberos主体名称 +- **krb5ConfFile**: Kerberos配置文件路径 + +这些参数在`BaseJdbcDataSourceInfo`类中定义,为Windows身份验证提供基础支持。 + +### AlwaysOn可用性组配置 +对于AlwaysOn可用性组,可以通过以下方式配置: +- 使用多个主机地址 +- 配置故障转移合作伙伴 +- 设置多子网故障转移 + +### 多子网故障转移配置 +多子网故障转移通过以下参数支持: +- **multiSubnetFailover**: 启用多子网故障转移 +- **loginTimeout**: 登录超时设置 + +```mermaid +flowchart TD +A["SQL Server连接配置"] --> B["基本连接参数"] +A --> C["SSL配置"] +A --> D["身份验证配置"] +A --> E["高可用性配置"] +B --> B1["host"] +B --> B2["port"] +B --> B3["database"] +B --> B4["user/password"] +C --> C1["encrypt=true/false"] +C --> C2["trustServerCertificate=true/false"] +D --> D1["SQL Server认证"] +D --> D2["Windows认证
(Kerberos支持)"] +E --> E1["AlwaysOn可用性组"] +E --> E2["多子网故障转移"] +E --> E3["故障转移合作伙伴"] +``` + +**图源** +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L184-L194) + +**本节源码** +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L184-L194) + +## 性能调优建议 +为优化SQL Server连接器的性能,建议采用以下策略: + +### 连接复用 +利用连接池实现连接复用,避免频繁创建和销毁连接。HikariCP连接池自动管理连接生命周期,确保连接的高效复用。 + +### 批量操作 +对于大量数据操作,建议使用批量处理: +- 批量插入(Batch Insert) +- 批量更新(Batch Update) +- 批量删除(Batch Delete) + +### 查询超时设置 +合理设置查询超时,避免长时间运行的查询影响系统性能: +- 设置合理的`queryTimeout`值 +- 监控长查询并进行优化 +- 使用索引优化查询性能 + +### 连接池优化 +连接池配置优化建议: +- 根据负载调整最大连接数 +- 设置适当的连接超时 +- 监控连接池使用情况 + +```mermaid +flowchart LR +A["性能调优"] --> B["连接管理"] +A --> C["查询优化"] +A --> D["资源监控"] +B --> B1["连接池复用"] +B --> B2["连接超时设置"] +B --> B3["连接泄漏检测"] +C --> C1["查询超时"] +C --> C2["索引优化"] +C --> C3["执行计划分析"] +D --> D1["连接池监控"] +D --> D2["查询性能监控"] +D --> D3["资源使用分析"] +``` + +**本节源码** +- [JdbcDataSourceManager.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\JdbcDataSourceManager.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) + +## 连接器连通性和性能测试 +为确保SQL Server连接器的正常工作,需要进行连通性和性能测试。 + +### 连通性测试 +连通性测试通过`getConnection()`方法实现: + +```java +public Connection getConnection() throws Exception { + Class.forName(getDriverClass()); + return DriverManager.getConnection(getJdbcUrl(), getUser(), getPassword()); +} +``` + +测试步骤: +1. 加载SQL Server JDBC驱动 +2. 使用配置的连接参数建立连接 +3. 执行验证查询(如"SELECT 1") +4. 返回连接状态 + +### 性能测试 +性能测试建议包括: +- 连接建立时间测试 +- 查询响应时间测试 +- 并发连接测试 +- 长时间运行稳定性测试 + +### 测试工具 +平台提供了测试连接的接口,可以通过以下方式测试: +- 使用管理界面的测试连接功能 +- 调用API进行连接测试 +- 使用命令行工具进行测试 + +```mermaid +sequenceDiagram +participant User as "用户" +participant UI as "用户界面" +participant Backend as "后端服务" +participant Connector as "SQL Server连接器" +participant Database as "SQL Server数据库" +User->>UI : 点击"测试连接" +UI->>Backend : 发送测试请求 +Backend->>Connector : 创建连接配置 +Connector->>Connector : 构建JDBC URL +Connector->>Database : 尝试建立连接 +alt 连接成功 +Database-->>Connector : 连接成功 +Connector-->>Backend : 返回成功状态 +Backend-->>UI : 显示成功消息 +UI-->>User : 显示测试成功 +else 连接失败 +Database-->>Connector : 连接失败 +Connector-->>Backend : 返回错误信息 +Backend-->>UI : 显示错误详情 +UI-->>User : 显示测试失败 +end +``` + +**图源** +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L149-L152) + +**本节源码** +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L149-L152) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256.md" new file mode 100644 index 00000000..b5c858c2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256/\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256.md" @@ -0,0 +1,430 @@ +# 关系型数据库配置 + + +**本文档中引用的文件** +- [JdbcConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcConnectionInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcDataSourceInfoManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceInfoManager.java) +- [JdbcExecutorClient.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClient.java) +- [JdbcExecutorClientManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClientManager.java) +- [ConnectionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ConnectionUtils.java) +- [MySqlDataSourceInfo.java](file://datavines-connector/ datavines-connector-plugins/ datavines-connector-mysql/src/main/java/io/ datavines/connector/plugin/MySqlDataSourceInfo.java) +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/ datavines-connector-plugins/ datavines-connector-postgresql/src/main/java/io/ datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [OracleDataSourceInfo.java](file://datavines-connector/ datavines-connector-plugins/ datavines-connector-oracle/src/main/java/io/ datavines/connector/plugin/OracleDataSourceInfo.java) +- [SqlServerDataSourceInfo.java](file://datavines-connector/ datavines-connector-plugins/ datavines-connector-sqlserver/src/main/java/io/ datavines/connector/plugin/SqlServerDataSourceInfo.java) +- [TestConnectionRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java) +- [ExecuteRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/ExecuteRequestParam.java) + + +## 目录 +1. [简介](#简介) +2. [核心配置组件](#核心配置组件) +3. [数据库连接配置](#数据库连接配置) + - [MySQL配置](#mysql配置) + - [PostgreSQL配置](#postgresql配置) + - [Oracle配置](#oracle配置) + - [SQL Server配置](#sql-server配置) +4. [连接池管理](#连接池管理) +5. [连接测试与验证](#连接测试与验证) +6. [性能调优建议](#性能调优建议) +7. [高级特性配置](#高级特性配置) + +## 简介 +DataVines 是一个数据质量平台,支持多种关系型数据库的连接与管理。本文档详细说明了如何配置 MySQL、PostgreSQL、Oracle 和 SQL Server 等主流关系型数据库的连接器,包括 JDBC 连接字符串格式、连接参数、SSL 配置、连接池参数以及高级特性如读写分离和故障转移。同时提供性能调优建议和连接测试方法。 + +## 核心配置组件 + +DataVines 的数据库连接配置基于一套统一的组件架构,主要包括以下几个核心类: + +- **JdbcConnectionInfo**: 存储基本的连接信息,如 host、port、database、username、password 等 +- **BaseJdbcDataSourceInfo**: 抽象基类,定义了所有 JDBC 数据源的通用行为和属性 +- **JdbcDataSourceInfoManager**: 管理数据源信息的缓存,使用 MD5 哈希作为唯一键 +- **JdbcExecutorClient**: 执行数据库操作的客户端,封装了连接获取和 JdbcTemplate +- **JdbcExecutorClientManager**: 管理 JdbcExecutorClient 实例的单例模式管理器 + +这些组件共同构成了 DataVines 数据库连接的基础架构,确保连接配置的一致性和高效性。 + +**Section sources** +- [JdbcConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcConnectionInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcDataSourceInfoManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceInfoManager.java) +- [JdbcExecutorClient.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClient.java) +- [JdbcExecutorClientManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClientManager.java) + +## 数据库连接配置 + +### MySQL配置 + +MySQL 数据库的连接配置遵循标准的 JDBC 规范,主要配置参数如下: + +- **JDBC URL 格式**: `jdbc:mysql://:/` +- **驱动类**: `com.mysql.cj.jdbc.Driver` +- **分隔符**: `?` (用于连接参数) +- **验证查询**: `Select 1` + +连接参数包括: +- host: 数据库服务器地址 +- port: 端口号(默认 3306) +- database: 数据库名称 +- user: 用户名 +- password: 密码 +- properties: 其他连接属性(如 SSL 配置、时区等) + +```mermaid +classDiagram +class MySqlDataSourceInfo { ++String getAddress() ++String getDriverClass() ++String getType() ++String getSeparator() +} +class BaseJdbcDataSourceInfo { ++String getUser() ++String getPassword() ++String getHost() ++String getPort() ++String getDatabase() ++String getJdbcUrl() ++Connection getConnection() +} +MySqlDataSourceInfo --|> BaseJdbcDataSourceInfo : 继承 +``` + +**Diagram sources** +- [MySqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MySqlDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +**Section sources** +- [MySqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MySqlDataSourceInfo.java) + +### PostgreSQL配置 + +PostgreSQL 数据库的连接配置具有以下特点: + +- **JDBC URL 格式**: `jdbc:postgresql://:/` +- **驱动类**: `org.postgresql.Driver` +- **分隔符**: `?` (用于连接参数) +- **验证查询**: `SELECT 'x'` + +PostgreSQL 特有的安全特性: +- 自动过滤敏感参数 `autoDeserialize=true` +- 支持 SSL 连接配置 +- 支持 Kerberos 认证 + +连接参数包括: +- host: 数据库服务器地址 +- port: 端口号(默认 5432) +- database: 数据库名称 +- user: 用户名 +- password: 密码 +- properties: 其他连接属性 + +```mermaid +classDiagram +class PostgreSqlDataSourceInfo { ++String getAddress() ++String getDriverClass() ++String getType() ++String getSeparator() ++String filterProperties(String) ++String getValidationQuery() +} +class BaseJdbcDataSourceInfo { ++String getUser() ++String getPassword() ++String getHost() ++String getPort() ++String getDatabase() ++String getJdbcUrl() ++Connection getConnection() +} +PostgreSqlDataSourceInfo --|> BaseJdbcDataSourceInfo : 继承 +``` + +**Diagram sources** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +**Section sources** +- [PostgreSqlDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java) + +### Oracle配置 + +Oracle 数据库的连接配置较为特殊,主要特点如下: + +- **JDBC URL 格式**: `jdbc:oracle:thin:@//:/` +- **驱动类**: `oracle.jdbc.driver.OracleDriver` +- **分隔符**: `?` (用于连接参数) +- **验证查询**: `Select 1 FROM DUAL` + +Oracle 特有的配置: +- 支持 SID (System Identifier) 配置 +- 使用 `DUAL` 表进行连接验证 +- 支持服务名连接 + +连接参数包括: +- host: 数据库服务器地址 +- port: 端口号(默认 1521) +- sid: 系统标识符 +- user: 用户名 +- password: 密码 +- properties: 其他连接属性 + +```mermaid +classDiagram +class OracleDataSourceInfo { ++String getAddress() ++String getDriverClass() ++String getType() ++String getSeparator() ++String getValidationQuery() ++String getJdbcUrl() ++void appendSid(StringBuilder) +} +class BaseJdbcDataSourceInfo { ++String getUser() ++String getPassword() ++String getHost() ++String getPort() ++String getDatabase() ++String getJdbcUrl() ++Connection getConnection() +} +OracleDataSourceInfo --|> BaseJdbcDataSourceInfo : 继承 +``` + +**Diagram sources** +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +**Section sources** +- [OracleDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java) + +### SQL Server配置 + +SQL Server 数据库的连接配置具有以下特点: + +- **JDBC URL 格式**: `jdbc:sqlserver://:;databaseName=` +- **驱动类**: `com.microsoft.sqlserver.jdbc.SQLServerDriver` +- **分隔符**: `;` (用于连接参数) +- **验证查询**: `Select 1` + +SQL Server 特有的配置: +- 使用分号 `;` 作为参数分隔符 +- 数据库名称通过 `databaseName` 参数指定 +- 支持 Windows 身份验证 + +连接参数包括: +- host: 数据库服务器地址 +- port: 端口号(默认 1433) +- database: 数据库名称 +- user: 用户名 +- password: 密码 +- properties: 其他连接属性 + +```mermaid +classDiagram +class SqlServerDataSourceInfo { ++String getAddress() ++String getDriverClass() ++String getType() ++String getSeparator() ++String getJdbcUrl() +} +class BaseJdbcDataSourceInfo { ++String getUser() ++String getPassword() ++String getHost() ++String getPort() ++String getDatabase() ++String getJdbcUrl() ++Connection getConnection() +} +SqlServerDataSourceInfo --|> BaseJdbcDataSourceInfo : 继承 +``` + +**Diagram sources** +- [SqlServerDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-sqlserver/src/main/java/io/datavines/connector/plugin/SqlServerDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +**Section sources** +- [SqlServerDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-sqlserver/src/main/java/io/datavines/connector/plugin/SqlServerDataSourceInfo.java) + +## 连接池管理 + +DataVines 通过 JdbcExecutorClientManager 实现了高效的连接池管理机制: + +- **连接缓存**: 使用 ConcurrentHashMap 缓存 JdbcExecutorClient 实例 +- **唯一键生成**: 基于连接参数的 MD5 哈希值作为缓存键 +- **连接复用**: 相同连接配置的请求复用已有连接 +- **线程安全**: 使用并发集合确保多线程环境下的安全性 + +连接池的关键特性: +- **连接获取**: 通过 `getExecutorClient()` 方法获取连接客户端 +- **连接释放**: 连接由连接池自动管理,无需手动释放 +- **连接验证**: 每次获取连接时进行有效性检查 +- **连接超时**: 支持配置连接超时时间 + +```mermaid +sequenceDiagram +participant Application as 应用程序 +participant ClientManager as JdbcExecutorClientManager +participant Client as JdbcExecutorClient +participant DataSource as JdbcDataSourceManager +participant Connection as 数据库连接 +Application->>ClientManager : getExecutorClient(info) +alt 缓存中存在 +ClientManager->>ClientManager : 返回缓存的客户端 +else 缓存中不存在 +ClientManager->>Client : 新建 JdbcExecutorClient +Client->>DataSource : getDataSource(info) +DataSource->>Connection : getConnection() +Client->>ClientManager : 缓存客户端 +end +ClientManager-->>Application : 返回 JdbcExecutorClient +Application->>Client : getConnection() +Client->>Connection : 返回数据库连接 +``` + +**Diagram sources** +- [JdbcExecutorClientManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClientManager.java) +- [JdbcExecutorClient.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClient.java) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +**Section sources** +- [JdbcExecutorClientManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClientManager.java) +- [JdbcExecutorClient.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClient.java) + +## 连接测试与验证 + +DataVines 提供了完善的连接测试机制,确保数据库连接的可靠性: + +### 连接测试流程 + +1. **参数准备**: 创建 TestConnectionRequestParam 对象 +2. **连接获取**: 调用 ConnectionUtils.getConnection() 方法 +3. **连接验证**: 执行验证查询(如 `Select 1`) +4. **结果返回**: 返回连接测试结果 + +### 测试参数配置 + +- **测试请求参数**: TestConnectionRequestParam 类继承自 ConnectorRequestParam +- **连接验证查询**: 各数据库类型有特定的验证查询语句 +- **超时处理**: 支持配置连接超时时间 +- **错误处理**: 捕获并处理连接异常 + +```mermaid +flowchart TD +Start([开始连接测试]) --> PrepareParams["准备连接参数"] +PrepareParams --> GetConnection["获取数据库连接"] +GetConnection --> ValidateConnection{"连接是否有效?"} +ValidateConnection --> |是| ExecuteQuery["执行验证查询"] +ValidateConnection --> |否| HandleError["处理连接错误"] +ExecuteQuery --> QuerySuccess{"查询成功?"} +QuerySuccess --> |是| ReturnSuccess["返回成功结果"] +QuerySuccess --> |否| HandleQueryError["处理查询错误"] +HandleError --> ReturnError["返回错误信息"] +HandleQueryError --> ReturnError +ReturnSuccess --> End([结束]) +ReturnError --> End +``` + +**Diagram sources** +- [TestConnectionRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java) +- [ConnectionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ConnectionUtils.java) + +**Section sources** +- [TestConnectionRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java) +- [ConnectionUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/ConnectionUtils.java) + +## 性能调优建议 + +为了优化数据库连接性能,建议采取以下措施: + +### 连接复用 +- **连接池配置**: 合理设置最大连接数和最小连接数 +- **连接保持**: 保持连接长时间存活,减少连接创建开销 +- **连接预热**: 在系统启动时预先创建连接 + +### 批量操作 +- **批量插入**: 使用批量插入语句提高写入性能 +- **批量查询**: 合并多个查询请求 +- **批处理大小**: 设置合适的批处理大小(如 fetchSize=500) + +### 查询优化 +- **查询超时**: 设置合理的查询超时时间 +- **结果集大小**: 限制返回结果集的大小 +- **索引优化**: 确保查询字段有适当的索引 + +### 连接参数优化 +- **连接超时**: 设置合理的连接超时时间 +- **读取超时**: 设置合理的读取超时时间 +- **TCP 保持**: 启用 TCP 保持连接 + +```mermaid +flowchart LR +A[连接性能调优] --> B[连接复用] +A --> C[批量操作] +A --> D[查询优化] +A --> E[参数优化] +B --> B1[连接池配置] +B --> B2[连接保持] +B --> B3[连接预热] +C --> C1[批量插入] +C --> C2[批量查询] +C --> C3[批处理大小] +D --> D1[查询超时] +D --> D2[结果集大小] +D --> D3[索引优化] +E --> E1[连接超时] +E --> E2[读取超时] +E --> E3[TCP 保持] +``` + +**Section sources** +- [ExecuteRequestParam.java](file://datavines-common/src/main/java/io/datavines/common/param/ExecuteRequestParam.java) +- [JdbcExecutorClient.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcExecutorClient.java) + +## 高级特性配置 + +### 读写分离 +- **配置方式**: 通过不同的数据源配置实现 +- **路由策略**: 应用层实现读写分离路由 +- **健康检查**: 定期检查主从数据库的健康状态 + +### 故障转移 +- **多数据源配置**: 配置主备数据库连接 +- **自动切换**: 当主数据库不可用时自动切换到备用数据库 +- **恢复机制**: 主数据库恢复后自动切换回主数据库 + +### SSL 配置 +- **SSL 启用**: 在连接参数中启用 SSL +- **证书验证**: 配置证书验证方式 +- **加密算法**: 选择合适的加密算法 + +### Kerberos 认证 +- **Kerberos 配置**: 配置 keytab 文件和 principal +- **krb5.conf**: 指定 krb5.conf 配置文件 +- **票据更新**: 自动处理 Kerberos 票据更新 + +```mermaid +graph TB +subgraph "高级特性" +A[读写分离] --> A1[主数据库] +A --> A2[从数据库] +A --> A3[路由策略] +B[故障转移] --> B1[主数据源] +B --> B2[备用数据源] +B --> B3[健康检查] +C[SSL 配置] --> C1[SSL 启用] +C --> C2[证书验证] +C --> C3[加密算法] +D[Kerberos 认证] --> D1[keytab 文件] +D --> D2[principal] +D --> D3[krb5.conf] +end +``` + +**Section sources** +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcConnectionInfo.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Flink\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Flink\351\205\215\347\275\256.md" new file mode 100644 index 00000000..e0a2e676 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Flink\351\205\215\347\275\256.md" @@ -0,0 +1,254 @@ +# Flink配置 + + +**本文档引用文件** +- [FlinkConfiguration.tsx](file://datavines-ui\src\view\Main\Config\FlinkConfiguration.tsx) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java) +- [FlinkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkParameters.java) +- [FlinkConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkConnectorFactory.java) +- [FlinkDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkDialect.java) +- [SqlTransform.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-transform-sql\src\main\java\io\datavines\engine\flink\transform\sql\SqlTransform.java) +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java) +- [pom.xml](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\pom.xml) + + +## 目录 +1. [Flink连接参数配置](#flink连接参数配置) +2. [Flink SQL Gateway连接配置](#flink-sql-gateway连接配置) +3. [Flink SQL方言与版本兼容性](#flink-sql方言与版本兼容性) +4. [安全配置](#安全配置) +5. [作业提交与性能优化](#作业提交与性能优化) + +## Flink连接参数配置 + +Flink连接参数配置主要包含JobManager地址、REST端口、集群名称等核心参数。在Datavines系统中,这些参数通过FlinkParameters类进行管理,支持多种部署模式的配置。 + +核心参数包括: +- **deployMode**: 部署模式,支持local、yarn-session、yarn-per-job、yarn-application +- **jobManagerMemory**: JobManager内存大小 +- **taskManagerMemory**: TaskManager内存大小 +- **parallelism**: 并行度设置 +- **jobName**: 作业名称 +- **yarnQueue**: YARN队列名称 +- **tags**: 作业标签 + +在前端配置界面中,用户可以通过表单设置这些参数,系统会将配置信息传递给后端执行器。 + +```mermaid +classDiagram +class FlinkParameters { ++String mainJar ++String mainClass ++String deployMode ++String taskManagerCount ++String taskManagerMemory ++String jobManagerMemory ++String mainArgs ++String yarnQueue ++String jobName ++int parallelism ++String flinkOthers ++String jars ++String tags +} +class FlinkArgsUtils { ++List buildArgs(FlinkParameters param) +} +FlinkArgsUtils --> FlinkParameters : "使用" +``` + +**图源** +- [FlinkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkParameters.java) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java) + +**节源** +- [FlinkParameters.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkParameters.java) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java) + +## Flink SQL Gateway连接配置 + +Flink SQL Gateway连接配置支持Standalone、YARN、Kubernetes等多种部署模式。不同模式的配置方式有所不同,主要通过命令行参数和系统属性进行配置。 + +### 部署模式配置 + +#### Standalone模式 +Standalone模式是最简单的部署方式,直接在本地运行Flink作业。配置参数相对简单,主要设置并行度和内存参数。 + +#### YARN模式 +YARN模式支持三种子模式: +- **yarn-session**: YARN会话模式,预先启动YARN集群,然后提交作业 +- **yarn-per-job**: 每个作业独立运行在YARN上 +- **yarn-application**: 应用程序模式,整个Flink应用作为一个YARN应用运行 + +YARN模式的配置需要额外设置以下参数: +- yarnQueue: YARN队列名称 +- jobName: 作业名称 +- tags: 作业标签 + +```mermaid +flowchart TD +Start([开始]) --> DeployMode{"部署模式"} +DeployMode --> |local| LocalConfig["配置本地参数
- parallelism
- jobManagerMemory
- taskManagerMemory"] +DeployMode --> |yarn-session| YarnSessionConfig["配置YARN会话参数
- yarnQueue
- jobName
- tags"] +DeployMode --> |yarn-per-job| YarnPerJobConfig["配置YARN每作业参数
- yarnQueue
- jobName
- tags"] +DeployMode --> |yarn-application| YarnApplicationConfig["配置YARN应用参数
- yarnQueue
- jobName
- tags"] +LocalConfig --> BuildCommand +YarnSessionConfig --> BuildCommand +YarnPerJobConfig --> BuildCommand +YarnApplicationConfig --> BuildCommand +BuildCommand["构建Flink命令"] --> End([结束]) +``` + +**图源** +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java) +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java) + +**节源** +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java) + +## Flink SQL方言与版本兼容性 + +Flink SQL方言配置通过FlinkDialect类实现,该类实现了Dialect接口,为Flink提供特定的SQL语法支持。 + +### SQL方言特性 + +FlinkDialect类目前实现了基本的接口方法,但具体实现为空。这表明系统可能依赖Flink内置的SQL解析器,而不是自定义方言。 + +主要接口方法包括: +- getDriver(): 获取JDBC驱动 +- getColumnPrefix()/getColumnSuffix(): 获取列名前缀/后缀 +- getExcludeDatabases(): 获取排除的数据库列表 +- getErrorDataScript(): 获取错误数据脚本 +- getValidateResultDataScript(): 获取验证结果数据脚本 + +### 版本兼容性 + +根据pom.xml文件中的依赖配置,当前系统使用Flink 1.16.1版本: + +```xml + + 1.16.1 + 2.12 + provided + +``` + +系统依赖的主要Flink组件包括: +- flink-streaming-java: 流处理核心 +- flink-clients: 客户端API +- flink-table-api-java: Table API +- flink-table-planner: 表规划器 +- flink-connector-jdbc: JDBC连接器 + +```mermaid +classDiagram +class FlinkDialect { ++String getDriver() ++String getColumnPrefix() ++String getColumnSuffix() ++List getExcludeDatabases() ++String getErrorDataScript(Map configMap) ++String getValidateResultDataScript(Map configMap) ++ResultList getPageFromResultSet(Statement sourceConnectionStatement, ResultSet rs, String sourceTable, int start, int end) +} +class Dialect { +<> ++String getDriver() ++String getColumnPrefix() ++String getColumnSuffix() ++List getExcludeDatabases() ++String getErrorDataScript(Map configMap) ++String getValidateResultDataScript(Map configMap) ++ResultList getPageFromResultSet(Statement sourceConnectionStatement, ResultSet rs, String sourceTable, int start, int end) +} +FlinkDialect --> Dialect : "实现" +``` + +**图源** +- [FlinkDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkDialect.java) +- [FlinkConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkConnectorFactory.java) + +**节源** +- [FlinkDialect.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-flink\src\main\java\io\datavines\connector\plugin\FlinkDialect.java) +- [pom.xml](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\pom.xml) + +## 安全配置 + +当前代码库中未发现明确的安全配置选项,如SSL加密或认证机制。系统主要通过以下方式确保安全性: + +1. **密码处理**: 在JDBC连接中,密码通过ParserUtils.decode方法进行解码,表明系统可能对密码进行了某种形式的编码或加密存储。 + +2. **配置隔离**: 不同的连接配置被隔离在各自的配置对象中,减少了配置泄露的风险。 + +3. **作业隔离**: 每个作业通过唯一的标签(tags)进行标识,有助于作业的追踪和管理。 + +未来可以考虑添加以下安全特性: +- SSL/TLS加密连接 +- Kerberos认证 +- 基于角色的访问控制(RBAC) +- 敏感信息加密存储 + +## 作业提交与性能优化 + +### 作业提交流程 + +作业提交通过FlinkEngineExecutor类实现,主要流程如下: + +1. 初始化作业执行请求 +2. 构建Flink命令行参数 +3. 执行Flink命令 +4. 处理执行结果 + +```mermaid +sequenceDiagram +participant UI as 用户界面 +participant Executor as FlinkEngineExecutor +participant ArgsUtils as FlinkArgsUtils +participant Command as Flink命令 +UI->>Executor : 提交作业配置 +Executor->>ArgsUtils : 调用buildArgs() +ArgsUtils-->>Executor : 返回参数列表 +Executor->>Executor : 构建完整命令 +Executor->>Command : 执行Flink命令 +Command-->>Executor : 返回执行结果 +Executor-->>UI : 显示执行状态 +``` + +**图源** +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java) +- [FlinkArgsUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\parameter\FlinkArgsUtils.java) + +**节源** +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java) + +### 性能优化建议 + +1. **合理设置并行度**: 根据数据量和集群资源合理设置parallelism参数,避免资源浪费或性能瓶颈。 + +2. **内存配置优化**: + - JobManager内存: 通常设置为1-2GB,除非有大量作业提交 + - TaskManager内存: 根据任务复杂度和数据量调整,建议从2GB开始逐步调整 + +3. **YARN资源管理**: + - 合理分配YARN队列资源 + - 设置适当的application.name便于监控和管理 + - 使用tags进行作业分类和追踪 + +4. **JAR包管理**: + - 将依赖JAR包集中管理 + - 避免重复加载相同的JAR包 + +5. **SQL优化**: + - 使用SqlTransform类进行SQL转换时,确保SQL语句经过优化 + - 避免在SQL中使用复杂的嵌套查询 + +6. **监控与调优**: + - 启用Flink的监控功能 + - 定期检查作业执行日志 + - 根据执行情况调整配置参数 + +通过合理配置这些参数和遵循优化建议,可以显著提升Flink作业的执行效率和稳定性。 + +**节源** +- [FlinkEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-executor\src\main\java\io\datavines\engine\flink\executor\FlinkEngineExecutor.java) +- [SqlTransform.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-flink\datavines-engine-flink-transform-sql\src\main\java\io\datavines\engine\flink\transform\sql\SqlTransform.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Hive\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Hive\351\205\215\347\275\256.md" new file mode 100644 index 00000000..f5224b00 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Hive\351\205\215\347\275\256.md" @@ -0,0 +1,280 @@ +# Hive配置 + + +**本文档引用文件** +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) +- [HiveParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveParameterConverter.java) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) +- [HiveConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConfigBuilder.java) +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) + + +## 目录 +1. [Hive连接器配置](#hive连接器配置) +2. [基本连接配置](#基本连接配置) +3. [Kerberos认证配置](#kerberos认证配置) +4. [Hive Metastore连接配置](#hive-metastore连接配置) +5. [性能优化建议](#性能优化建议) +6. [连接测试方法](#连接测试方法) +7. [常见问题排查指南](#常见问题排查指南) + +## Hive连接器配置 + +本文档详细说明Hive连接器的配置方法,包括JDBC URL、数据库名称、用户名密码等基本配置,重点描述Kerberos认证配置方法,包括keytab文件配置、principal设置等安全认证方式。同时说明Hive Metastore的连接配置,支持Thrift和HTTP模式,并提供性能优化建议和连接测试方法。 + +**本文档引用文件** +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java) +- [HiveParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveParameterConverter.java) + +## 基本连接配置 + +Hive连接器的基本配置包括JDBC URL、数据库名称、用户名和密码等参数。JDBC URL的格式为`jdbc:hive2://host:port/database`,其中host和port分别表示Hive服务器的主机地址和端口号,database表示要连接的数据库名称。 + +在配置中,需要提供以下基本参数: +- **主机地址(host)**: Hive服务器的主机地址,支持多个地址用逗号分隔 +- **端口号(port)**: Hive服务器的端口号,默认为10000 +- **数据库名称(database)**: 要连接的Hive数据库名称 +- **用户名(user)**: 连接Hive的用户名 +- **密码(password)**: 连接Hive的密码 + +JDBC URL的构建通过`HiveParameterConverter`类的`getUrl`方法实现,该方法根据提供的参数构建完整的JDBC连接字符串。 + +**本文档引用文件** +- [HiveParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveParameterConverter.java#L28-L44) +- [HiveDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceInfo.java#L31-L39) + +## Kerberos认证配置 + +Hive连接器支持Kerberos认证,通过keytab文件和principal进行安全认证。Kerberos认证配置需要提供以下参数: + +- **keytab文件路径(keytab_file)**: keytab文件的完整路径 +- **principal(keytab_principal)**: 与keytab文件关联的principal名称 +- **krb5.conf文件路径(krb5_conf)**: Kerberos配置文件krb5.conf的路径 + +Kerberos认证的实现由`KerberosUtils`类负责,该类提供了检查Kerberos配置、从keytab文件获取principal列表和初始化Kerberos认证的功能。在连接测试时,系统会先检查Kerberos配置是否完整,然后调用`initKerberos`方法进行认证初始化。 + +```mermaid +sequenceDiagram +participant 配置界面 +participant HiveConnector +participant KerberosUtils +participant Hive服务器 +配置界面->>HiveConnector : 提交连接配置 +HiveConnector->>KerberosUtils : checkKerberosConfig() +alt 配置完整 +KerberosUtils-->>HiveConnector : 返回true +HiveConnector->>KerberosUtils : initKerberos() +KerberosUtils-->>HiveConnector : 认证初始化成功 +HiveConnector->>Hive服务器 : 建立连接 +Hive服务器-->>HiveConnector : 连接成功 +HiveConnector-->>配置界面 : 测试成功 +else 配置不完整 +KerberosUtils-->>HiveConnector : 返回false +HiveConnector-->>配置界面 : 配置不完整,请检查Kerberos参数 +end +``` + +**图表来源** +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java#L39-L77) +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java#L58-L60) + +**本文档引用文件** +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) + +## Hive Metastore连接配置 + +Hive Metastore的连接配置通过`HiveConfigBuilder`类实现,支持Thrift和HTTP模式。配置构建器定义了所有必要的连接参数,包括主机、端口、数据库、用户、密码以及Kerberos相关参数。 + +Hive Metastore连接配置的主要参数包括: +- **主机(host)**: Metastore服务的主机地址 +- **端口(port)**: Metastore服务的端口,默认为9083 +- **catalog**: Hive catalog名称 +- **schema**: Hive schema名称 +- **properties**: 额外的连接属性,如`hive.resultset.use.unique.column.names=false` + +```mermaid +classDiagram +class HiveConfigBuilder { ++build(isEn boolean) String ++getPropertiesInput(isEn boolean) InputParam ++getOtherParams(isEn boolean) PluginParams[] ++getKeytabFile(isEn boolean) InputParam ++getKeytabPrincipal(isEn boolean) InputParam ++getKrb5Conf(isEn boolean) InputParam +} +class ConfigBuilder { +<> ++build(isEn boolean) String +} +class PluginParams { ++String name ++String title ++String description ++int type ++Validate[] validate ++String defaultValue +} +class InputParam { ++String name ++String title ++String description ++int type ++Validate[] validate ++String defaultValue +} +ConfigBuilder <|-- HiveConfigBuilder +HiveConfigBuilder --> PluginParams +HiveConfigBuilder --> InputParam +``` + +**图表来源** +- [HiveConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConfigBuilder.java#L31-L117) + +**本文档引用文件** +- [HiveConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConfigBuilder.java) + +## 性能优化建议 + +为了提高Hive连接器的性能,建议进行以下优化配置: + +### 连接池配置 +通过`BaseJdbcDataSourceInfo`类的连接管理机制,系统自动管理连接池。连接池的配置基于数据源的唯一键(unique key),该键由主机、端口、数据库、用户等参数的MD5哈希值生成。 + +### 查询并发度设置 +在`BaseJdbcDataSourceInfo`类中,可以通过设置`properties`参数来优化查询性能。例如,可以设置`fetchSize`参数来控制每次从服务器获取的行数,减少网络传输次数。 + +### 其他性能优化 +- **启用Spark Hive支持**: 通过设置`enable_spark_hive_support`参数为true,可以在Spark环境中更好地支持Hive操作 +- **连接属性优化**: 在`properties`字段中配置适当的连接属性,如`hive.resultset.use.unique.column.names=false`,可以提高查询性能 + +```mermaid +flowchart TD +A[连接请求] --> B{是否存在连接池?} +B --> |是| C[从连接池获取连接] +B --> |否| D[创建新连接池] +D --> E[初始化BasicDataSource] +E --> F[设置驱动类名] +F --> G[添加连接属性] +G --> H[设置JDBC URL] +H --> I[存储到连接池] +I --> J[返回连接] +C --> J +J --> K[执行查询] +K --> L[返回结果] +``` + +**图表来源** +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L96-L103) +- [TrinoDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoDataSourceClient.java#L94-L123) + +**本文档引用文件** +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) + +## 连接测试方法 + +Hive连接器提供了连接测试功能,通过`HiveConnector`类的`testConnect`方法实现。连接测试的流程如下: + +1. 解析连接参数 +2. 检查Kerberos配置(如果启用) +3. 初始化Kerberos认证(如果配置完整) +4. 加载JDBC驱动类 +5. 建立数据库连接 +6. 关闭连接并返回测试结果 + +连接测试方法会返回一个`ConnectorResponse`对象,包含测试状态和结果。测试成功时返回成功状态和true结果,测试失败时返回失败状态和false结果。 + +```mermaid +sequenceDiagram +participant 测试请求 +participant HiveConnector +participant KerberosUtils +participant DriverManager +participant Hive服务器 +测试请求->>HiveConnector : testConnect() +HiveConnector->>HiveConnector : 解析参数 +HiveConnector->>KerberosUtils : checkKerberosConfig() +alt Kerberos已配置 +KerberosUtils-->>HiveConnector : 配置有效 +HiveConnector->>KerberosUtils : initKerberos() +KerberosUtils-->>HiveConnector : 认证成功 +end +HiveConnector->>HiveConnector : loadClass() +HiveConnector->>DriverManager : getConnection() +alt 连接成功 +DriverManager-->>HiveConnector : 返回Connection +HiveConnector->>Hive服务器 : 关闭连接 +HiveConnector-->>测试请求 : 成功响应 +else 连接失败 +DriverManager-->>HiveConnector : 抛出SQLException +HiveConnector-->>测试请求 : 失败响应 +end +``` + +**图表来源** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java#L55-L72) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L149-L152) + +**本文档引用文件** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) + +## 常见问题排查指南 + +### Kerberos认证失败 +**问题现象**: 连接测试时提示Kerberos认证失败 +**可能原因**: +- keytab文件路径不正确 +- principal名称与keytab文件不匹配 +- krb5.conf文件路径错误 +- Kerberos服务不可用 + +**解决方案**: +1. 检查keytab文件路径是否正确,文件是否存在 +2. 确认principal名称是否与keytab文件中的principal匹配 +3. 验证krb5.conf文件路径和内容是否正确 +4. 使用`klist`命令检查Kerberos票据是否正常获取 + +### 连接超时 +**问题现象**: 连接Hive服务器超时 +**可能原因**: +- 网络不通或防火墙阻止 +- Hive服务器未启动或端口不正确 +- 服务器负载过高 + +**解决方案**: +1. 检查网络连接是否正常,使用ping命令测试 +2. 确认Hive服务器是否正常运行,端口是否正确 +3. 检查服务器资源使用情况,确保有足够的资源 + +### 权限不足 +**问题现象**: 连接成功但无法访问数据库或表 +**可能原因**: +- 用户没有足够的权限 +- 数据库或表不存在 +- Hive配置限制了访问 + +**解决方案**: +1. 确认用户是否有访问指定数据库和表的权限 +2. 检查数据库和表名称是否正确 +3. 查看Hive的授权配置,确保用户有相应权限 + +### 驱动类加载失败 +**问题现象**: 提示无法加载Hive JDBC驱动类 +**可能原因**: +- hive-jdbc依赖未正确引入 +- 驱动类名错误 +- 类路径问题 + +**解决方案**: +1. 确认pom.xml中已正确引入hive-jdbc依赖 +2. 检查驱动类名是否为`org.apache.hive.jdbc.HiveDriver` +3. 确保类路径配置正确 + +**本文档引用文件** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Presto\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Presto\351\205\215\347\275\256.md" new file mode 100644 index 00000000..2990b90e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Presto\351\205\215\347\275\256.md" @@ -0,0 +1,209 @@ +# Presto配置 + + +**本文档引用文件** +- [PrestoConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConfigBuilder.java) +- [PrestoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java) +- [PrestoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceInfo.java) +- [PrestoParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoParameterConverter.java) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java) + + +## 目录 +1. [Presto连接参数配置](#presto连接参数配置) +2. [认证配置方法](#认证配置方法) +3. [SSL/TLS加密连接配置](#ssltls加密连接配置) +4. [高级配置选项](#高级配置选项) +5. [性能调优建议](#性能调优建议) +6. [连接测试方法](#连接测试方法) + +## Presto连接参数配置 + +Presto连接器的配置主要包括Coordinator地址、端口、目录名称(catalog)、模式名称(schema)等核心参数。这些参数通过JDBC URL格式进行组织,确保与Presto集群的正确通信。 + +### 核心连接参数 + +Presto连接的核心参数包括: + +- **主机地址(host)**:Presto Coordinator节点的IP地址或主机名 +- **端口(port)**:Presto服务监听的端口号,默认为8080 +- **目录名称(catalog)**:Presto中的数据源目录,如hive、mysql等 +- **数据库/模式名称(database)**:指定要连接的具体数据库或模式 + +JDBC连接URL的生成遵循以下格式: +- 当指定数据库时:`jdbc:presto://://` +- 当未指定数据库时:`jdbc:presto://:/` + +这些参数在`PrestoDataSourceInfo`类中通过`getJdbcUrl()`方法构建,使用`StringBuilder`依次拼接地址、目录、数据库和附加属性。 + +### 参数映射与验证 + +`PrestoConfigBuilder`类负责定义配置参数的输入表单和验证规则: +- `catalog`字段为必填项,提示信息为"请填入目录类型" +- `database`字段为可选项,提示信息为"请填入数据库" +- `password`字段为可选项,用于基本认证 + +参数的键值对存储在`Map`结构中,并通过`BaseJdbcDataSourceInfo`基类提供的方法进行访问和处理。 + +**本节来源** +- [PrestoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceInfo.java#L30-L46) +- [PrestoConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConfigBuilder.java#L24-L48) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java#L95-L98) + +## 认证配置方法 + +Presto连接器支持多种认证方式,包括基本认证、Kerberos认证等,通过JDBC连接属性进行配置。 + +### 基本认证(Basic Authentication) + +基本认证通过在连接属性中设置用户名和密码实现。在`PrestoConnector`类的`testConnect`方法中,通过`Properties`对象设置认证信息: +- 使用`USER`常量作为用户名键 +- 使用`PASSWORD`常量作为密码键 +- 将这些属性附加到JDBC URL的查询参数中 + +```java +properties.setProperty(USER, dataSourceInfo.getUser()); +if (StringUtils.isNotEmpty(dataSourceInfo.getPassword())) { + properties.setProperty(PASSWORD, dataSourceInfo.getPassword()); +} +``` + +### Kerberos认证 + +虽然Presto连接器本身未直接实现Kerberos认证逻辑,但系统通过共享的Kerberos工具类支持此功能。从`KerberosUtils`类可以看出,系统支持以下Kerberos相关配置: +- **keytab文件路径**:通过`KEYTAB_FILE`常量定义 +- **主体名称(Principal)**:通过`KEYTAB_PRINCIPAL`常量定义 +- **krb5.conf文件路径**:通过`KRB5_CONF`常量定义 + +这些配置项存储在数据源参数映射中,可通过`BaseJdbcDataSourceInfo`类的相应getter方法访问。 + +### JWT令牌认证 + +系统架构支持通过`PROPERTIES`参数传递自定义连接属性,这为JWT令牌认证提供了可能性。用户可以将JWT令牌作为连接属性直接附加到JDBC URL中,例如: +``` +jdbc:presto://host:port/catalog?accessToken=your.jwt.token.here +``` + +**本节来源** +- [PrestoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java#L64-L78) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java#L184-L194) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java#L177-L181) + +## SSL/TLS加密连接配置 + +Presto连接器支持SSL/TLS加密连接,通过在连接属性中配置相应的SSL参数实现。虽然具体实现未在Presto专用类中体现,但系统通过通用的JDBC连接框架支持SSL配置。 + +### SSL配置方式 + +SSL配置通过`PROPERTIES`参数传递,可以包含以下常见的SSL相关属性: +- `SSL=true`:启用SSL加密 +- `SSLTrustStorePath`:信任库路径 +- `SSLTrustStorePassword`:信任库密码 +- `SSLEngineHostVerification=false`:禁用主机名验证(测试环境) + +这些属性会直接附加到JDBC URL的查询字符串中,由Presto JDBC驱动程序处理。 + +### 证书管理 + +系统本身不直接管理SSL证书,而是依赖JVM的信任库机制。用户需要: +1. 将Presto服务器的CA证书导入到JVM的信任库中 +2. 或者通过连接属性指定自定义的信任库路径和密码 +3. 确保运行环境的`java.security.krb5.conf`等安全配置正确 + +**本节来源** +- [PrestoParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoParameterConverter.java#L44-L47) +- [PrestoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceInfo.java#L43) + +## 高级配置选项 + +Presto连接器支持多种高级配置选项,包括会话属性、查询超时、资源组配置等,这些都通过通用的属性机制进行管理。 + +### 会话属性配置 + +会话属性可以通过`PROPERTIES`参数进行设置,影响查询执行的会话级别行为。常见的会话属性包括: +- `query_max_run_time`:查询最大运行时间 +- `query_priority`:查询优先级 +- `resource_group`:资源组名称 +- `timezone`:会话时区 + +### 查询超时设置 + +查询超时可以通过以下方式配置: +- `query_max_execution_time`:查询最大执行时间 +- `client_timeout`:客户端超时时间 +- `query_max_cpu_time`:查询最大CPU时间 + +这些超时设置有助于防止长时间运行的查询占用过多资源。 + +### 资源组配置 + +资源组(Resource Group)用于控制查询的资源分配和并发度。可以通过以下属性进行配置: +- `resource_group`:指定查询所属的资源组 +- `query_type`:查询类型(如SELECT、INSERT等) +- `source`:查询来源标识 + +**本节来源** +- [PrestoParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoParameterConverter.java#L44-L47) +- [PrestoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceInfo.java#L43) + +## 性能调优建议 + +为了优化Presto连接的性能,建议采取以下措施: + +### 连接池配置 + +系统使用`commons-dbcp2`作为连接池实现,建议配置以下参数: +- `maxTotal`:最大连接数,根据并发需求设置 +- `maxIdle`:最大空闲连接数 +- `minIdle`:最小空闲连接数 +- `maxWaitMillis`:获取连接的最大等待时间 + +### 批量操作优化 + +对于大量数据操作,建议: +- 使用批量执行模式减少网络往返 +- 合理设置`fetchSize`以优化结果集获取 +- 利用Presto的并行查询能力 + +### 查询优化 + +- 避免SELECT *,只选择需要的列 +- 使用适当的过滤条件减少数据扫描 +- 利用Presto的分区和分桶特性 +- 对频繁查询的表使用合适的索引策略 + +**本节来源** +- [pom.xml](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/pom.xml#L50-L53) +- [PrestoDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceClient.java) + +## 连接测试方法 + +系统提供了内置的连接测试功能,通过`PrestoConnector`类的`testConnect`方法实现。 + +### 测试流程 + +连接测试的执行流程如下: +1. 解析数据源参数为Map结构 +2. 创建`PrestoDataSourceInfo`实例 +3. 加载JDBC驱动类 +4. 构建包含认证信息的`Properties`对象 +5. 从JDBC URL中分离基础URL和查询参数 +6. 使用`DriverManager.getConnection()`建立连接 +7. 执行`SHOW SCHEMAS`命令验证连接有效性 +8. 关闭连接并返回测试结果 + +### 测试结果 + +测试结果通过`ConnectorResponse`对象返回,包含: +- `status`:测试状态(SUCCESS/FAILURE) +- `result`:布尔值,表示连接是否成功 +- 错误信息记录在日志中 + +测试方法确保不仅能够建立连接,还能成功执行基本的元数据查询,验证了连接的完整可用性。 + +**本节来源** +- [PrestoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java#L59-L97) +- [PrestoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceInfo.java#L49) +- [PrestoDataSourceClient.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceClient.java#L58-L64) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Spark\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Spark\351\205\215\347\275\256.md" new file mode 100644 index 00000000..068974c6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Spark\351\205\215\347\275\256.md" @@ -0,0 +1,298 @@ +# Spark配置 + + +**本文档引用的文件** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java) +- [SparkConstants.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkConstants.java) +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java) +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java) +- [HiveConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConfigBuilder.java) +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java) +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java) +- [HiveSqlDialect.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/dialect/HiveSqlDialect.java) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java) + + +## 目录 +1. [Spark连接参数配置](#spark连接参数配置) +2. [Spark Thrift Server连接配置](#spark-thrift-server连接配置) +3. [Spark SQL方言配置](#spark-sql方言配置) +4. [Spark安全配置](#spark安全配置) +5. [Spark性能调优建议](#spark性能调优建议) + +## Spark连接参数配置 + +Spark连接参数配置是确保Spark应用程序正确运行的关键。在Datavines系统中,Spark连接参数主要通过`SparkEngineParameter`类进行定义和管理。核心参数包括Master URL、应用名称、执行器内存等。 + +### 核心连接参数 + +Spark连接的核心参数通过`SparkConstants`类中的常量定义,这些参数在启动Spark应用程序时作为命令行参数传递: + +```mermaid +flowchart TD +A[Spark连接参数] --> B[Master URL] +A --> C[应用名称] +A --> D[部署模式] +A --> E[驱动程序配置] +A --> F[执行器配置] +E --> G[驱动程序核心数] +E --> H[驱动程序内存] +F --> I[执行器数量] +F --> J[执行器核心数] +F --> K[执行器内存] +``` + +**参数说明:** + +- **Master URL**: 通过`--master`参数指定,定义Spark集群的主节点地址。支持多种部署模式,包括`yarn`、`local`等。 +- **应用名称**: 通过`--name`参数指定,为Spark应用程序设置名称,便于在集群管理界面中识别。 +- **部署模式**: 通过`--deploy-mode`参数指定,可选值为`cluster`或`client`,决定驱动程序在集群内部还是外部运行。 +- **驱动程序配置**: 包括`--driver-cores`(驱动程序核心数)和`--driver-memory`(驱动程序内存),用于配置驱动程序的计算资源。 +- **执行器配置**: 包括`--num-executors`(执行器数量)、`--executor-cores`(每个执行器的核心数)和`--executor-memory`(每个执行器的内存),用于配置执行器的资源分配。 + +这些参数在`SparkArgsUtils.buildArgs()`方法中被组装成命令行参数列表,确保所有配置项正确传递给Spark-submit命令。 + +**参数配置示例:** +```java +SparkParameters param = new SparkParameters(); +param.setMaster("yarn"); +param.setAppName("MySparkApp"); +param.setDeployMode("cluster"); +param.setNumExecutors(4); +param.setExecutorCores(2); +param.setExecutorMemory("4g"); +param.setDriverMemory("2g"); +``` + +**Spark连接参数配置** +- [SparkEngineParameter.java](file://datavines-common/src/main/java/io/datavines/common/entity/SparkEngineParameter.java#L26-L68) +- [SparkConstants.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkConstants.java#L28-L75) +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java#L43-L128) + +## Spark Thrift Server连接配置 + +Spark Thrift Server连接配置支持YARN、Standalone、Kubernetes等多种部署模式。在Datavines系统中,通过统一的参数配置机制实现不同部署模式的适配。 + +### 部署模式配置 + +Spark支持多种部署模式,每种模式都有其特定的配置要求: + +```mermaid +graph TD +A[Spark部署模式] --> B[YARN] +A --> C[Standalone] +A --> D[Kubernetes] +A --> E[Local] +B --> F[通过yarn模式提交] +C --> G[通过独立集群管理] +D --> H[通过Kubernetes API] +E --> I[本地模式运行] +``` + +在`SparkArgsUtils`类中,通过常量定义了不同部署模式的标识: + +- `SPARK_CLUSTER = "cluster"`: 集群模式 +- `SPARK_LOCAL = "local"`: 本地模式 +- `SPARK_ON_YARN = "yarn"`: YARN模式 + +当部署模式不为`local`时,系统会自动添加`yarn`作为Master URL,并配置相应的部署模式参数。 + +### YARN模式配置 + +YARN模式是企业环境中最常用的部署模式。在YARN模式下,需要配置队列信息以确保应用程序提交到正确的资源队列: + +```java +if (!SPARK_LOCAL.equals(deployMode) && (StringUtils.isEmpty(others) || !others.contains(SparkConstants.SPARK_QUEUE))) { + String queue = param.getQueue(); + if (StringUtils.isNotEmpty(queue)) { + args.add(SparkConstants.SPARK_QUEUE); + args.add(queue); + } +} +``` + +此配置确保在非本地模式下,如果未通过其他参数指定队列,则使用`--queue`参数指定的队列名称。 + +### 资源调度平台 + +系统通过`ResourceSchedulePlatformType`枚举定义了不同的资源调度平台类型,支持灵活的平台适配。在YARN环境下,系统会读取`yarn.uri`配置项来确定ResourceManager的地址。 + +**Spark Thrift Server连接配置** +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java#L27-L31) +- [SparkConstants.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkConstants.java#L38-L38) +- [YarnUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/YarnUtils.java#L37-L47) + +## Spark SQL方言配置 + +Spark SQL方言配置主要用于处理不同数据源的SQL语法差异,确保SQL语句的正确解析和执行。在Datavines系统中,针对Hive数据源实现了专门的SQL方言支持。 + +### Hive SQL方言实现 + +系统通过`HiveSqlDialect`类实现了Hive特有的SQL方言处理: + +```mermaid +classDiagram +class JdbcDialect { ++canHandle(String url) boolean ++quoteIdentifier(String colName) String +} +class HiveSqlDialect { ++canHandle(String url) boolean ++quoteIdentifier(String colName) String +} +JdbcDialect <|-- HiveSqlDialect +``` + +**HiveSqlDialect的主要功能:** + +1. **URL匹配**: `canHandle()`方法检查JDBC URL是否以`jdbc:hive2`开头,确保只处理Hive连接。 +2. **标识符引用**: `quoteIdentifier()`方法处理列名的引用,特别处理包含点号的列名(如`table.column`),提取实际的列名部分并用反引号包围。 + +在`SparkRuntimeEnvironment.prepare()`方法中,系统会注册Hive SQL方言: + +```java +JdbcDialects.registerDialect(new HiveSqlDialect()); +``` + +这确保了Spark SQL引擎能够正确处理Hive特有的语法和标识符引用规则。 + +### Spark Hive支持配置 + +系统支持通过配置项启用Spark对Hive的支持。在`HiveConfigBuilder`中,提供了`enable_spark_hive_support`配置参数: + +```java +InputParam enableSparkHiveSupport = getInputParam("enable_spark_hive_support", + "spark.enable.hive.support", + isEn ? "please enter true or false" : "请填入 true 或者 false", 2, null, + "true"); +``` + +此配置项默认值为`true`,可以在创建Hive连接时根据需要启用或禁用Spark Hive支持。 + +**Spark SQL方言配置** +- [HiveSqlDialect.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/dialect/HiveSqlDialect.java#L23-L38) +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java#L68-L71) +- [HiveConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConfigBuilder.java#L84-L87) + +## Spark安全配置 + +Spark安全配置包括SSL/TLS加密和Kerberos认证等选项,确保数据传输和访问的安全性。在Datavines系统中,针对企业级安全需求提供了完整的安全配置支持。 + +### Kerberos认证配置 + +系统通过`KerberosUtils`类和`HiveConfigBuilder`实现了Kerberos认证支持: + +```mermaid +flowchart TD +A[安全配置] --> B[Kerberos认证] +A --> C[SSL/TLS加密] +B --> D[keytab文件] +B --> E[Principal] +B --> F[krb5.conf] +C --> G[SSL连接] +C --> H[证书验证] +``` + +**Kerberos配置参数:** + +- **keytab文件**: 通过`keytab_file`参数指定keytab文件路径 +- **Principal**: 通过`keytab_principal`参数指定主体名称 +- **krb5.conf**: 通过`krb5_conf`参数指定Kerberos配置文件路径 + +在`HiveConfigBuilder`中,这些参数被作为连接配置的一部分: + +```java +params.add(getKeytabFile(isEn)); +params.add(getKeytabPrincipal(isEn)); +params.add(getKrb5Conf(isEn)); +``` + +在`LivyTaskSubmitHelper`中,系统根据配置决定是否使用Kerberos认证: + +```java +if (needKerberos.equalsIgnoreCase("false")) { + // 无需Kerberos认证 + result = restTemplate.postForObject(uri, springEntity, String.class); +} else { + // 需要Kerberos认证 + String userPrincipal = configurations.getString("livy.server.auth.kerberos.principal"); + String keyTabLocation = configurations.getString("livy.server.auth.kerberos.keytab"); + KerberosRestTemplate restTemplate = new KerberosRestTemplate(keyTabLocation, userPrincipal); + result = restTemplate.getForObject(uri, String.class); +} +``` + +### 安全配置验证 + +在`HiveConnector`中,系统会验证Kerberos配置的完整性: + +```java +if(KerberosUtils.checkKerberosConfig(dataSourceInfo.getKeytabPrincipal(), + dataSourceInfo.getKeytabFile(), dataSourceInfo.getKrb5ConfFile())){ + // Kerberos配置有效 +} +``` + +这种分层的安全配置机制确保了在不同安全需求下的灵活适配,同时保持了配置的一致性和可管理性。 + +**Spark安全配置** +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java#L35-L35) +- [HiveConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConfigBuilder.java#L93-L114) +- [LivyTaskSubmitHelper.java](file://datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/helper/LivyTaskSubmitHelper.java#L127-L190) +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java#L58-L58) + +## Spark性能调优建议 + +Spark性能调优是确保大数据处理任务高效运行的关键。在Datavines系统中,通过合理的资源配置和参数优化,可以显著提升Spark应用程序的性能。 + +### 动态资源分配 + +系统支持通过配置参数实现动态资源分配,根据工作负载自动调整执行器数量: + +```mermaid +flowchart LR +A[资源需求] --> B{负载分析} +B --> |高负载| C[增加执行器] +B --> |低负载| D[减少执行器] +C --> E[性能提升] +D --> F[资源节约] +``` + +通过`num-executors`、`executor-cores`和`executor-memory`参数的合理配置,可以实现资源的最优分配: + +```java +int numExecutors = param.getNumExecutors(); +if (numExecutors > 0) { + args.add(SparkConstants.NUM_EXECUTORS); + args.add(String.format("%d", numExecutors)); +} +``` + +### 并行度优化 + +并行度优化主要通过调整执行器核心数和数量来实现: + +- **执行器核心数**: 通过`executor-cores`参数配置,建议设置为2-4个核心,避免过多的核心导致GC开销增加 +- **执行器内存**: 通过`executor-memory`参数配置,建议每个执行器内存不超过32GB,以避免长时间的垃圾回收停顿 +- **驱动程序内存**: 通过`driver-memory`参数配置,确保驱动程序有足够的内存处理元数据和结果收集 + +### 配置最佳实践 + +根据Spark官方推荐的配置最佳实践: + +1. **内存分配**: 执行器内存的75%用于执行,25%用于存储 +2. **核心利用率**: 每个执行器的核心数不应超过5个,以保持良好的并行度和资源利用率 +3. **数据本地性**: 通过合理的分区策略和数据布局,最大化数据本地性,减少网络传输开销 + +在`SparkRuntimeEnvironment`中,系统还设置了关键的Spark配置: + +```java +conf.set("spark.sql.crossJoin.enabled","true"); +``` + +此配置允许执行笛卡尔积操作,在某些分析场景下可能需要,但应谨慎使用以避免性能问题。 + +**Spark性能调优建议** +- [SparkParameters.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkParameters.java#L55-L65) +- [SparkArgsUtils.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/parameter/SparkArgsUtils.java#L73-L88) +- [SparkRuntimeEnvironment.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java#L84-L84) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Trino\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Trino\351\205\215\347\275\256.md" new file mode 100644 index 00000000..395317de --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/Trino\351\205\215\347\275\256.md" @@ -0,0 +1,296 @@ +# Trino配置 + + +**本文档引用的文件** +- [TrinoDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoDataSourceInfo.java) +- [TrinoConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoConfigBuilder.java) +- [TrinoParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoParameterConverter.java) +- [TrinoConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoConnector.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [JdbcConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConfigBuilder.java) + + +## 目录 +1. [Trino连接参数配置](#trino连接参数配置) +2. [Trino认证配置](#trino认证配置) +3. [SSL/TLS加密连接配置](#ssltls加密连接配置) +4. [Trino高级配置选项](#trino高级配置选项) +5. [Trino性能调优建议](#trino性能调优建议) +6. [连接测试方法](#连接测试方法) + +## Trino连接参数配置 + +Trino连接器的配置主要包括Coordinator地址、端口、目录名称、模式名称等核心参数。这些参数通过JDBC URL格式进行配置,确保能够正确连接到Trino集群。 + +Trino连接器使用标准的JDBC连接方式,其基本连接格式为:`jdbc:trino://host:port`。在此基础上,可以添加目录(catalog)和数据库(database)等信息以实现更精确的连接。 + +核心连接参数包括: +- **主机地址(host)**:Trino Coordinator节点的IP地址或主机名 +- **端口(port)**:Trino服务监听的端口号,默认为8080 +- **目录名称(catalog)**:指定要连接的数据源目录,如hive、mysql等 +- **数据库名称(database)**:指定要连接的具体数据库 +- **用户名(user)**:用于身份验证的用户名 +- **密码(password)**:与用户名对应的密码 + +当配置数据库名称时,JDBC URL将包含完整的路径信息,格式为`jdbc:trino://host:port/catalog/database`;若不指定数据库,则格式为`jdbc:trino://host:port/catalog`。 + +```mermaid +flowchart TD +Start([开始配置Trino连接]) --> HostPort["配置主机地址和端口"] +HostPort --> Catalog["配置目录名称"] +Catalog --> Database{"是否需要指定\n数据库名称?"} +Database --> |是| DatabaseName["配置数据库名称"] +Database --> |否| Properties{"是否需要添加\n连接属性?"} +DatabaseName --> Properties +Properties --> |是| ConnectionProperties["配置连接属性"] +Properties --> |否| BuildURL["构建完整的JDBC URL"] +ConnectionProperties --> BuildURL +BuildURL --> End([完成Trino连接配置]) +``` + +**图源** +- [TrinoDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoDataSourceInfo.java#L30-L46) +- [TrinoParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoParameterConverter.java#L31-L47) + +**本节来源** +- [TrinoDataSourceInfo.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoDataSourceInfo.java#L30-L46) +- [TrinoParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoParameterConverter.java#L31-L47) + +## Trino认证配置 + +Trino支持多种认证方式,包括基本认证、LDAP、Kerberos和JWT令牌等。在Datavines系统中,主要通过配置相应的参数来实现不同类型的认证。 + +### 基本身份认证 +基本身份认证是最简单的认证方式,通过用户名和密码进行验证。在配置中需要提供`user`和`password`参数。 + +### LDAP认证 +LDAP认证允许使用LDAP服务器进行用户身份验证。要启用LDAP认证,需要在连接属性中添加相应的LDAP配置参数,如`auth=LDAP`,并确保服务器端已正确配置LDAP服务。 + +### Kerberos认证 +对于需要更高安全级别的环境,可以使用Kerberos认证。虽然在当前代码库中没有直接针对Trino的Kerberos实现,但系统支持通过keytab文件、principal和krb5.conf配置来实现Kerberos认证,这在其他连接器(如Hive)中有示例。 + +### JWT令牌认证 +JWT(JSON Web Token)令牌认证提供了一种无状态的身份验证机制。可以通过在连接属性中添加`auth=JWT`并提供相应的令牌来实现。 + +认证配置的关键在于正确设置连接属性(properties),这些属性会作为查询参数附加到JDBC URL后面。例如:`jdbc:trino://host:port/catalog?auth=LDAP&user=username`。 + +```mermaid +graph TD +A[认证方式选择] --> B{选择认证类型} +B --> C[基本认证] +B --> D[LDAP认证] +B --> E[Kerberos认证] +B --> F[JWT令牌认证] +C --> G["需配置: user, password"] +D --> H["需配置: auth=LDAP, user, password"] +E --> I["需配置: keytab文件, principal, krb5.conf"] +F --> J["需配置: auth=JWT, token"] +G --> K[构建认证参数] +H --> K +I --> K +J --> K +K --> L[集成到连接属性] +L --> M[完成认证配置] +``` + +**图源** +- [TrinoConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoConnector.java#L63-L77) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java#L91-L92) + +**本节来源** +- [TrinoConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoConnector.java#L63-L77) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java#L91-L92) + +## SSL/TLS加密连接配置 + +为了确保数据传输的安全性,Trino支持通过SSL/TLS加密连接。在Datavines系统中,可以通过配置连接属性来启用SSL/TLS加密。 + +SSL/TLS配置主要通过在连接属性(properties)中添加相应的参数来实现。常见的配置参数包括: +- `SSL=true`:启用SSL连接 +- `SSLVerification=FULL`:启用完整的证书验证 +- 其他SSL相关参数可根据具体需求添加 + +在系统架构中,HTTP客户端已经集成了SSL支持,使用`SSLConnectionSocketFactory`和`SSLContext`来处理安全连接。虽然这是针对HTTP通信的,但体现了系统对安全连接的支持能力。 + +Trino JDBC驱动会自动处理SSL连接的建立,只需要在连接字符串中正确配置SSL参数即可。证书管理通常由JVM的信任库(truststore)和密钥库(keystore)负责,可以在JVM启动参数中指定相应的证书文件。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Driver as "Trino JDBC驱动" +participant Server as "Trino服务器" +Client->>Driver : 配置连接参数(含SSL) +Driver->>Driver : 创建SSLContext +Driver->>Server : 发起SSL握手 +Server-->>Driver : 提供证书 +Driver->>Driver : 验证服务器证书 +Driver-->>Server : 完成SSL握手 +Driver->>Server : 加密数据传输 +Server-->>Driver : 加密响应 +Driver->>Client : 返回结果 +``` + +**图源** +- [HttpUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\HttpUtils.java#L79-L107) +- [TrinoParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoParameterConverter.java#L44-L47) + +**本节来源** +- [HttpUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\HttpUtils.java#L79-L107) + +## Trino高级配置选项 + +Trino连接器提供了多种高级配置选项,以满足不同的使用场景和性能需求。这些选项主要通过连接属性(properties)进行配置。 + +### 会话属性 +会话属性允许在连接时设置特定的执行环境参数。这些属性可以控制查询行为、资源使用等。通过在连接属性中添加相应的键值对来设置会话属性。 + +### 查询超时设置 +查询超时设置用于防止长时间运行的查询占用过多资源。可以在连接属性中设置查询超时时间,单位通常为秒。这有助于提高系统的稳定性和响应性。 + +### 资源组配置 +资源组配置允许将查询分配到不同的资源组中,从而实现资源的隔离和配额管理。这对于多租户环境或需要精细控制资源使用的场景非常重要。 + +### 其他高级选项 +- **网络超时**:配置连接超时和读取超时 +- **缓冲区大小**:调整数据传输的缓冲区大小 +- **压缩设置**:启用数据传输压缩以减少网络带宽使用 + +这些高级配置选项都通过统一的属性机制进行管理,即在`properties`字段中以`key=value&key2=value2`的格式添加多个配置项。 + +```mermaid +classDiagram +class TrinoConfigBuilder { ++getHostInput(isEn) ++getPortInput(isEn) ++getCatalogInput(isEn) ++getDatabaseInput(isEn) ++getUserInput(isEn) ++getPasswordInput(isEn) ++getPropertiesInput(isEn) ++build(isEn) +} +class JdbcConfigBuilder { ++getHostInput(isEn) ++getPortInput(isEn) ++getDatabaseInput(isEn) ++getUserInput(isEn) ++getPasswordInput(isEn) ++getPropertiesInput(isEn) ++build(isEn) +} +class ConfigBuilder { +<> ++build(isEn) ++buildErrorDataStorage(isEn) +} +TrinoConfigBuilder --|> JdbcConfigBuilder : 继承 +JdbcConfigBuilder --|> ConfigBuilder : 实现 +TrinoConfigBuilder --> "1" ConfigConstants : 使用 +JdbcConfigBuilder --> "1" CommonConstants : 使用 +``` + +**图源** +- [TrinoConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoConfigBuilder.java#L24-L30) +- [JdbcConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConfigBuilder.java#L38-L70) + +**本节来源** +- [TrinoConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoConfigBuilder.java#L24-L30) +- [JdbcConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\JdbcConfigBuilder.java#L38-L70) + +## Trino性能调优建议 + +为了获得最佳的Trino查询性能,建议采取以下调优措施: + +### 连接池配置 +使用连接池可以显著提高性能,避免频繁创建和销毁连接的开销。系统中使用了`commons-dbcp2`作为连接池实现,应合理配置连接池大小、最大空闲连接数等参数。 + +### 批量操作 +对于大量数据的操作,应尽量使用批量处理而不是逐条处理。这可以减少网络往返次数,提高整体吞吐量。 + +### 查询优化 +- **合理使用过滤条件**:在查询中尽早应用过滤条件,减少数据传输量 +- **选择合适的目录和表**:避免扫描不必要的数据 +- **使用适当的JOIN策略**:根据数据量选择最适合的JOIN方式 + +### 资源管理 +- **设置合理的查询超时**:防止长时间运行的查询影响系统稳定性 +- **监控资源使用情况**:及时发现并解决资源瓶颈 +- **使用资源组隔离**:将不同类型的查询分配到不同的资源组 + +### 缓存策略 +对于频繁访问的元数据信息,可以考虑使用缓存机制,减少对Trino服务器的重复查询。 + +```mermaid +flowchart LR +A[性能调优领域] --> B[连接管理] +A --> C[查询优化] +A --> D[资源管理] +A --> E[缓存策略] +B --> B1[使用连接池] +B --> B2[合理配置连接参数] +C --> C1[优化查询语句] +C --> C2[减少数据扫描] +D --> D1[设置查询超时] +D --> D2[使用资源组] +E --> E1[缓存元数据] +E --> E2[减少重复查询] +style A fill:#f9f,stroke:#333 +style B fill:#bbf,stroke:#333 +style C fill:#bbf,stroke:#333 +style D fill:#bbf,stroke:#333 +style E fill:#bbf,stroke:#333 +``` + +**图源** +- [pom.xml](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\pom.xml#L50-L53) +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java#L42-L44) + +**本节来源** +- [pom.xml](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\pom.xml#L50-L53) +- [BaseJdbcExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-jdbc\src\main\java\io\datavines\connector\plugin\BaseJdbcExecutor.java#L42-L44) + +## 连接测试方法 + +Trino连接器提供了完善的连接测试功能,确保配置的正确性。连接测试主要通过`testConnect`方法实现。 + +连接测试的流程如下: +1. 解析数据源参数 +2. 创建数据源信息对象 +3. 加载JDBC驱动类 +4. 构建连接属性 +5. 尝试建立数据库连接 +6. 执行简单的元数据查询(如SHOW SCHEMAS) +7. 返回测试结果 + +测试过程中会捕获所有异常,并返回详细的错误信息。成功的连接测试不仅要求能够建立连接,还需要能够成功执行基本的SQL查询。 + +连接测试是验证配置正确性的关键步骤,在生产环境中部署前必须进行充分的测试。建议在不同网络条件下进行多次测试,确保连接的稳定性和可靠性。 + +```mermaid +sequenceDiagram +participant UI as "用户界面" +participant Service as "连接服务" +participant Driver as "JDBC驱动" +participant Trino as "Trino服务器" +UI->>Service : 发送测试连接请求 +Service->>Service : 解析连接参数 +Service->>Service : 创建数据源信息 +Service->>Service : 加载驱动类 +Service->>Driver : 获取连接 +Driver->>Trino : 建立连接 +Trino-->>Driver : 连接成功 +Driver-->>Service : 返回连接对象 +Service->>Service : 执行SHOW SCHEMAS查询 +Service->>Trino : 发送查询 +Trino-->>Service : 返回结果 +Service->>UI : 返回测试成功 +``` + +**图源** +- [TrinoConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoConnector.java#L58-L96) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L149-L152) + +**本节来源** +- [TrinoConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-trino\src\main\java\io\datavines\connector\plugin\TrinoConnector.java#L58-L96) +- [BaseJdbcDataSourceInfo.java](file://datavines-common\src\main\java\io\datavines\common\datasource\jdbc\BaseJdbcDataSourceInfo.java#L149-L152) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256.md" new file mode 100644 index 00000000..c5bc27c2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256/\345\244\247\346\225\260\346\215\256\345\271\263\345\217\260\351\205\215\347\275\256.md" @@ -0,0 +1,342 @@ +# 大数据平台配置 + + +**本文档中引用的文件** +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveDataSourceInfo.java) +- [TrinoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoConnector.java) +- [TrinoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoDataSourceInfo.java) +- [PrestoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java) +- [PrestoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java) +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java) +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) + + +## 目录 +1. [引言](#引言) +2. [核心连接器配置](#核心连接器配置) +3. [Hive平台配置](#hive平台配置) +4. [Spark平台配置](#spark平台配置) +5. [Flink平台配置](#flink平台配置) +6. [Trino与Presto平台配置](#trino与presto平台配置) +7. [认证与安全配置](#认证与安全配置) +8. [高可用性与负载均衡](#高可用性与负载均衡) +9. [性能调优建议](#性能调优建议) +10. [连接器测试与验证](#连接器测试与验证) + +## 引言 +本文档详细说明了大数据平台连接器的配置方法,涵盖Hive、Spark、Flink、Trino、Presto等主流大数据平台的连接参数、认证方式、执行引擎配置等关键配置项。文档还解释了如何配置高可用性、负载均衡等高级选项,并提供性能调优建议和连接测试方法。 + +## 核心连接器配置 +大数据平台连接器基于统一的JDBC连接框架,通过继承`BaseJdbcDataSourceInfo`类实现各平台特定的连接配置。连接器通过`Connector`接口定义标准操作,包括获取数据库、表、列元数据以及测试连接等功能。 + +```mermaid +classDiagram +class Connector { ++getDatabases(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++testConnect(param) ConnectorResponse ++keyProperties() String[] +} +class JdbcConnector { ++getDatasourceInfo(param) BaseJdbcDataSourceInfo ++testConnect(param) ConnectorResponse +} +class BaseJdbcDataSourceInfo { ++getUser() String ++getPassword() String ++getHost() String ++getPort() String ++getDatabase() String ++getCatalog() String ++getJdbcUrl() String ++getDriverClass() String ++getType() String +} +Connector <|-- JdbcConnector +BaseJdbcDataSourceInfo <|-- HiveDataSourceInfo +BaseJdbcDataSourceInfo <|-- TrinoDataSourceInfo +BaseJdbcDataSourceInfo <|-- PrestoDataSourceInfo +JdbcConnector <|-- HiveConnector +JdbcConnector <|-- TrinoConnector +JdbcConnector <|-- PrestoConnector +``` + +**图源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +**本节来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +## Hive平台配置 +Hive连接器通过`HiveConnector`类实现,支持标准JDBC连接和Kerberos认证。配置参数包括主机、端口、数据库、用户、密码以及Kerberos相关配置。 + +### 连接参数 +Hive连接器的关键配置参数如下: + +| 参数 | 描述 | 是否必需 | +|------|------|---------| +| host | Hive服务器主机地址,支持逗号分隔的多个主机 | 是 | +| port | Hive服务器端口,默认10000 | 是 | +| database | 要连接的数据库名称 | 是 | +| user | 认证用户名 | 否 | +| password | 认证密码 | 否 | +| keytab_file | Kerberos keytab文件路径 | 否 | +| keytab_principal | Kerberos主体名称 | 否 | +| krb5_conf | Kerberos配置文件路径 | 否 | +| properties | 其他JDBC连接属性 | 否 | + +### JDBC URL格式 +Hive连接器生成的JDBC URL格式为: +``` +jdbc:hive2://host1:port,host2:port/database;properties +``` + +### Kerberos认证 +Hive连接器支持Kerberos认证,通过`KerberosUtils`类实现。当配置了Kerberos相关参数时,连接器会自动初始化Kerberos环境。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant HiveConnector as "Hive连接器" +participant KerberosUtils as "Kerberos工具" +participant HiveServer as "Hive服务器" +Client->>HiveConnector : testConnect请求 +HiveConnector->>HiveConnector : 解析连接参数 +HiveConnector->>KerberosUtils : checkKerberosConfig +alt Kerberos配置有效 +KerberosUtils-->>HiveConnector : 配置有效 +HiveConnector->>KerberosUtils : initKerberos +KerberosUtils-->>HiveConnector : Kerberos初始化成功 +else 配置无效 +KerberosUtils-->>HiveConnector : 配置无效 +end +HiveConnector->>HiveServer : 建立JDBC连接 +HiveServer-->>HiveConnector : 连接成功 +HiveConnector-->>Client : 返回测试结果 +``` + +**图源** +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java) + +**本节来源** +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [HiveDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveDataSourceInfo.java) +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java) + +## Spark平台配置 +Spark平台配置主要通过Spark执行引擎实现,支持与Hive集成。配置参数包括Spark主节点地址、执行模式、资源分配等。 + +### Spark-Hive集成 +通过配置`enable_spark_hive_support`参数启用Spark对Hive的支持。当启用时,Spark可以访问Hive元数据和表。 + +### 连接参数 +Spark连接器的关键配置参数: + +| 参数 | 描述 | 是否必需 | +|------|------|---------| +| spark.master | Spark主节点URL | 是 | +| spark.app.name | 应用程序名称 | 否 | +| spark.executor.instances | 执行器实例数量 | 否 | +| spark.executor.memory | 每个执行器内存 | 否 | +| spark.driver.memory | 驱动程序内存 | 否 | +| spark.sql.warehouse.dir | 仓库目录 | 否 | + +## Flink平台配置 +Flink平台配置通过Flink执行引擎实现,支持批处理和流处理模式。配置参数包括JobManager地址、并行度、检查点间隔等。 + +### 连接参数 +Flink连接器的关键配置参数: + +| 参数 | 描述 | 是否必需 | +|------|------|---------| +| jobmanager.rpc.address | JobManager地址 | 是 | +| jobmanager.rpc.port | JobManager端口 | 是 | +| parallelism.default | 默认并行度 | 否 | +| state.checkpoints.dir | 检查点目录 | 否 | +| execution.checkpointing.interval | 检查点间隔 | 否 | + +## Trino与Presto平台配置 +Trino和Presto连接器具有相似的配置结构,都基于JDBC协议,支持catalog和schema级别的数据访问。 + +### Trino配置 +Trino连接器通过`TrinoConnector`类实现,配置参数包括: + +| 参数 | 描述 | 是否必需 | +|------|------|---------| +| host | Trino服务器主机 | 是 | +| port | Trino服务器端口,默认8080 | 是 | +| catalog | 要连接的catalog | 是 | +| database | 要连接的数据库 | 是 | +| user | 认证用户名 | 否 | +| password | 认证密码 | 否 | + +### Presto配置 +Presto连接器通过`PrestoConnector`类实现,配置参数与Trino类似: + +| 参数 | 描述 | 是否必需 | +|------|------|---------| +| host | Presto服务器主机 | 是 | +| port | Presto服务器端口,默认8080 | 是 | +| catalog | 要连接的catalog | 是 | +| database | 要连接的数据库 | 是 | +| user | 认证用户名 | 否 | +| password | 认证密码 | 否 | + +### JDBC URL格式 +Trino和Presto连接器生成的JDBC URL格式为: +``` +jdbc:trino://host:port/catalog/database?properties +jdbc:presto://host:port/catalog/database?properties +``` + +```mermaid +classDiagram +class TrinoDataSourceInfo { ++getAddress() String ++getJdbcUrl() String ++getDriverClass() String ++getType() String ++getSeparator() String +} +class PrestoDataSourceInfo { ++getAddress() String ++getJdbcUrl() String ++getDriverClass() String ++getType() String ++getSeparator() String +} +class BaseJdbcDataSourceInfo { ++getUser() String ++getPassword() String ++getHost() String ++getPort() String ++getDatabase() String ++getCatalog() String ++getJdbcUrl() String +} +BaseJdbcDataSourceInfo <|-- TrinoDataSourceInfo +BaseJdbcDataSourceInfo <|-- PrestoDataSourceInfo +``` + +**图源** +- [TrinoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoDataSourceInfo.java) +- [PrestoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceInfo.java) + +**本节来源** +- [TrinoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoConnector.java) +- [TrinoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoDataSourceInfo.java) +- [PrestoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java) +- [PrestoDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceInfo.java) + +## 认证与安全配置 +大数据平台连接器支持多种认证方式,包括基本认证、Kerberos认证等。 + +### Kerberos认证 +Kerberos认证通过`KerberosUtils`类实现,需要配置以下参数: + +- **keytab_file**: Kerberos keytab文件路径 +- **keytab_principal**: Kerberos主体名称 +- **krb5_conf**: Kerberos配置文件路径 + +认证流程如下: +1. 检查Kerberos配置是否完整 +2. 设置Java系统属性`java.security.krb5.conf` +3. 配置Hadoop安全认证为Kerberos +4. 使用keytab文件登录用户 + +```mermaid +flowchart TD +Start([开始]) --> CheckConfig["检查Kerberos配置"] +CheckConfig --> ConfigValid{"配置有效?"} +ConfigValid --> |否| ReturnFail["返回失败"] +ConfigValid --> |是| SetKrb5Conf["设置krb5.conf"] +SetKrb5Conf --> SetHadoopAuth["设置Hadoop认证"] +SetHadoopAuth --> LoginUser["使用keytab登录"] +LoginUser --> LoginSuccess{"登录成功?"} +LoginSuccess --> |否| ReturnFail +LoginSuccess --> |是| EstablishConnection["建立数据库连接"] +EstablishConnection --> ReturnSuccess["返回成功"] +ReturnFail --> End([结束]) +ReturnSuccess --> End +``` + +**图源** +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java) + +**本节来源** +- [KerberosUtils.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java) + +## 高可用性与负载均衡 +大数据平台连接器支持高可用性和负载均衡配置,通过多主机配置和连接池实现。 + +### 多主机配置 +对于支持多主机的平台(如Hive),可以在host参数中配置多个主机地址,用逗号分隔: +``` +host1,host2,host3 +``` + +### 连接池配置 +连接器自动管理数据库连接,通过连接池提高性能和可靠性。连接池配置参数包括: + +| 参数 | 描述 | +|------|------| +| validationQuery | 连接验证查询,默认"Select 1" | +| maxPoolSize | 最大连接池大小 | +| minPoolSize | 最小连接池大小 | +| idleTimeout | 空闲连接超时时间 | + +## 性能调优建议 +为优化大数据平台连接器的性能,建议采用以下配置策略。 + +### 并行度设置 +根据数据量和处理需求合理设置并行度: + +- 小数据集:并行度设置为2-4 +- 中等数据集:并行度设置为8-16 +- 大数据集:并行度设置为32以上 + +### 资源分配 +合理分配计算资源,避免资源争用: + +| 平台 | 建议配置 | +|------|----------| +| Spark | executor.instances=4, executor.memory=4g | +| Flink | parallelism.default=8, taskmanager.memory.process.size=4g | +| Hive | mapreduce.map.memory.mb=2048, mapreduce.reduce.memory.mb=4096 | + +### 数据本地性优化 +尽量将计算任务调度到数据所在的节点,减少网络传输开销。对于HDFS存储的数据,确保执行节点与数据节点在同一机架。 + +## 连接器测试与验证 +连接器提供了测试连接功能,用于验证配置的正确性和连接的可用性。 + +### 测试流程 +1. 准备连接参数 +2. 调用testConnect方法 +3. 验证返回结果 +4. 记录测试日志 + +### 测试代码示例 +```java +TestConnectionRequestParam param = new TestConnectionRequestParam(); +param.setDataSourceParam("{\"host\":\"localhost\",\"port\":\"10000\",\"database\":\"default\",\"user\":\"hive\"}"); +ConnectorResponse response = connector.testConnect(param); +if (response.getResult()) { + System.out.println("连接测试成功"); +} else { + System.out.println("连接测试失败"); +} +``` + +**本节来源** +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [TrinoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoConnector.java) +- [PrestoConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\344\272\221\345\255\230\345\202\250\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\344\272\221\345\255\230\345\202\250\351\205\215\347\275\256.md" new file mode 100644 index 00000000..62a14885 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\344\272\221\345\255\230\345\202\250\351\205\215\347\275\256.md" @@ -0,0 +1,411 @@ +# 云存储配置 + + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [ConfigBuilder.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java) +- [JdbcConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java) +- [FileConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnectorFactory.java) +- [ErrorDataStorageController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/ErrorDataStorageController.java) +- [ErrorDataStorageServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/ErrorDataStorageServiceImpl.java) +- [ErrorDataStorageCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/storage/ErrorDataStorageCreate.java) +- [ErrorDataStorageUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/storage/ErrorDataStorageUpdate.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +DataVines 是一个易于使用的数据质量服务平台,支持多种指标。该平台基于插件设计,允许用户自定义扩展多个模块,包括数据源、检查规则、作业执行引擎、警报通道、错误数据存储和注册中心。本配置文档将详细说明如何配置云存储访问密钥、安全令牌、区域(Region)设置、存储桶(Bucket)权限等,并解释不同云服务商的配置差异、SDK版本兼容性、传输加密(SSL/TLS)设置等。此外,还将提供云存储性能优化建议,如多部分上传、预签名URL、CDN集成等,以及云存储连接测试、成本控制和安全最佳实践。 + +## 项目结构 +DataVines 项目的结构清晰地划分为多个模块,每个模块负责不同的功能。以下是主要模块的简要介绍: + +- **bin/**: 包含启动脚本,如 `datavines-daemon.sh` 和 `datavines-submit.sh`。 +- **datavines-cli/**: 命令行接口模块。 +- **datavines-client/**: 客户端模块,包含 HTTP 客户端核心组件。 +- **datavines-common/**: 公共模块,包含配置、数据源、实体、枚举、异常、日志、参数、工具类等。 +- **datavines-connector/**: 连接器模块,支持多种数据源,如 MySQL、Impala、StarRocks、Doris、Presto、Trino、ClickHouse、PostgreSQL 等。 +- **datavines-core/**: 核心模块,包含 AOP、常量、实体、枚举、异常、工具类等。 +- **datavines-dist/**: 分发模块,包含构建脚本。 +- **datavines-engine/**: 执行引擎模块,支持 Spark 和 Local 两种执行模式。 +- **datavines-metric/**: 指标模块,支持多种数据质量检查规则。 +- **datavines-notification/**: 通知模块,支持邮件、钉钉、飞书、企业微信等通知方式。 +- **datavines-registry/**: 注册中心模块,支持 MySQL、PostgreSQL 和 ZooKeeper。 +- **datavines-runner/**: 作业运行器模块,负责作业的执行。 +- **datavines-server/**: 服务器模块,包含 API、配置、DQC、注册、仓库、调度、工具类等。 +- **datavines-spi/**: SPI 模块,支持插件加载。 +- **datavines-ui/**: 用户界面模块,包含前端组件、钩子、HTTP 请求、语言、存储、类型、工具类等。 +- **deploy/**: 部署模块,包含 Docker Compose 和 Kubernetes 配置。 +- **scripts/sql/**: SQL 脚本模块,包含数据库初始化脚本。 +- **tools/checkstyle/**: 代码检查工具模块,包含 Checkstyle 配置。 + +```mermaid +graph TB +subgraph "前端" +UI[用户界面] +Router[路由] +end +subgraph "后端" +API[API 服务器] +Auth[认证服务] +DB[(数据库)] +end +UI --> API +API --> Auth +API --> DB +``` + +**图源** +- [datavines-ui](file://datavines-ui) +- [datavines-server](file://datavines-server) + +**节源** +- [README.md](file://README.md) + +## 核心组件 +DataVines 的核心组件包括数据目录、数据质量、数据剖析、插件设计、多种执行模式、易部署和高可用性。 + +### 数据目录 +- 定期获取数据源元数据,构建数据目录。 +- 定期监控元数据变化。 +- 支持标签管理,与元数据结合。 + +### 数据质量 +- 内置 27 种数据质量检查规则。 +- 支持 4 种数据质量检查规则类型: + - 单表列检查 + - 单表自定义 SQL 检查 + - 跨表准确性检查 + - 两表值比较检查 +- 支持计划任务进行检查。 +- 支持 SLA 用于检查结果警报。 + +### 数据剖析 +- 支持定时执行数据检测,输出数据剖析报告。 +- 支持自动识别列类型,自动匹配适当的数据剖析指标。 +- 支持表行数趋势监控。 +- 支持数据分布视图。 + +### 插件设计 +- **数据源**: 支持 MySQL、Impala、StarRocks、Doris、Presto、Trino、ClickHouse、PostgreSQL 等。 +- **检查规则**: 内置 27 种检查规则,如空值检查、非空检查、枚举检查等。 +- **作业执行引擎**: 支持 Spark 和 Local 两种执行模式。Spark 引擎目前仅支持 Spark 2.4 版本,Local 引擎是基于 JDBC 开发的本地执行引擎,不依赖其他执行引擎。 +- **警报通道**: 支持邮件。 +- **错误数据存储**: 支持 MySQL 和本地文件(仅 Local 执行引擎支持)。 +- **注册中心**: 支持 MySQL、PostgreSQL 和 ZooKeeper。 + +### 多种执行模式 +- 提供网页配置检查作业,运行作业,查看作业执行日志,查看错误数据和检查结果。 +- 支持在线生成作业运行脚本,通过 `datavines-submit.sh` 提交作业,可与调度系统结合使用。 + +### 易部署和高可用性 +- 平台依赖较少,易于部署。 +- 最小化仅依赖 MySQL 启动项目,完成数据质量操作检查。 +- 支持水平扩展,自动容错。 +- 分布式设计,Server 节点支持水平扩展以提高性能。 +- 作业自动容错,确保作业不会丢失或重复。 + +**节源** +- [README.md](file://README.md) + +## 架构概述 +DataVines 的架构设计旨在提供一个灵活、可扩展的数据质量服务平台。系统架构主要包括前端、后端、数据源、执行引擎、通知服务、注册中心和错误数据存储。 + +```mermaid +graph TB +subgraph "前端" +UI[用户界面] +Router[路由] +end +subgraph "后端" +API[API 服务器] +Auth[认证服务] +DB[(数据库)] +end +UI --> API +API --> Auth +API --> DB +``` + +**图源** +- [datavines-ui](file://datavines-ui) +- [datavines-server](file://datavines-server) + +**节源** +- [README.md](file://README.md) + +## 详细组件分析 + +### 错误数据存储配置 +错误数据存储是 DataVines 中的一个重要组件,用于存储数据质量检查过程中发现的错误数据。目前支持 MySQL 和本地文件两种存储方式。 + +#### 配置文件 +错误数据存储的配置主要在 `application.yaml` 文件中进行。以下是配置文件的相关部分: + +```yaml +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://127.0.0.1:5432/datavines + username: postgres + password: 123456 + hikari: + connection-test-query: select 1 + minimum-idle: 5 + auto-commit: true + validation-timeout: 3000 + pool-name: datavines + maximum-pool-size: 50 + connection-timeout: 30000 + idle-timeout: 600000 + leak-detection-threshold: 0 + initialization-fail-timeout: 1 +``` + +#### 配置接口 +`ConfigBuilder` 接口定义了生成配置的方法。不同的数据源需要实现该接口来生成相应的配置。 + +```java +public interface ConfigBuilder { + String build(boolean isEn); + String buildErrorDataStorage(boolean isEn); +} +``` + +#### 具体实现 +以 MySQL 为例,`MysqlConfigBuilder` 类实现了 `ConfigBuilder` 接口,生成 MySQL 数据源的配置。 + +```java +public class MysqlConfigBuilder extends JdbcConfigBuilder { + @Override + public String buildErrorDataStorage(boolean isEn) { + List params = new ArrayList<>(); + params.add(getHostInput(isEn)); + params.add(getPortInput(isEn)); + if (getCatalogInput(isEn) != null) { + params.add(getCatalogInput(isEn)); + } + params.add(getErrorDataStorageDatabaseInput(isEn)); + if (getSchemaInput(isEn) != null) { + params.add(getSchemaInput(isEn)); + } + params.add(getUserInput(isEn)); + params.add(getPasswordInput(isEn)); + params.add(getPropertiesInput(isEn)); + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + String result = null; + try { + result = mapper.writeValueAsString(params); + } catch (JsonProcessingException e) { + log.error("json parse error : ", e); + } + return result; + } +} +``` + +#### 控制器 +`ErrorDataStorageController` 类提供了 REST API 接口,用于管理错误数据存储的配置。 + +```java +@Api(value = "errorDataStorage", tags = "errorDataStorage", produces = MediaType.APPLICATION_JSON_VALUE) +@RestController +@RequestMapping(value = DataVinesConstants.BASE_API_PATH + "/errorDataStorage", produces = MediaType.APPLICATION_JSON_VALUE) +@RefreshToken +public class ErrorDataStorageController { + @Autowired + private ErrorDataStorageService errorDataStorageService; + + @ApiOperation(value = "test error data storage") + @PostMapping(value = "/test", consumes = MediaType.APPLICATION_JSON_VALUE) + public Object testConnection(@Valid @RequestBody TestConnectionRequestParam param) { + return errorDataStorageService.testConnect(param); + } + + @ApiOperation(value = "create error data storage") + @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) + public Object create(@Valid @RequestBody ErrorDataStorageCreate errorDataStorageCreate) throws DataVinesServerException { + return errorDataStorageService.create(errorDataStorageCreate); + } + + @ApiOperation(value = "update error data storage") + @PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE) + public Object update(@Valid @RequestBody ErrorDataStorageUpdate errorDataStorageUpdate) throws DataVinesServerException { + return errorDataStorageService.update(errorDataStorageUpdate); + } + + @ApiOperation(value = "delete error data storage") + @DeleteMapping(value = "/{id}") + public Object delete(@PathVariable long id) { + return errorDataStorageService.deleteById(id); + } + + @ApiOperation(value = "get error data storage page") + @PostMapping(value = "page") + public Object page(@Valid @RequestBody ErrorDataStoragePageParam errorDataStoragePageParam) { + return errorDataStorageService.getErrorDataStoragePage(errorDataStoragePageParam); + } + + @ApiOperation(value = "get storage config json") + @GetMapping(value = "/config/{type}") + public Object getConfigJson(@PathVariable String type){ + return errorDataStorageService.getConfigJson(type); + } + + @ApiOperation(value = "get error data storage type list") + @GetMapping(value = "/type/list") + public Object getErrorDataStorageTypeList() { + Set errorDataStorageList = PluginLoader.getPluginLoader(ConnectorFactory.class).getSupportedPlugins(); + List items = new ArrayList<>(); + for (String errorDataStorage : errorDataStorageList) { + ConnectorFactory connectorFactory = PluginLoader.getPluginLoader(ConnectorFactory.class).getOrCreatePlugin(errorDataStorage); + if (connectorFactory == null) { + continue; + } + if (connectorFactory.getDialect().supportToBeErrorDataStorage()) { + Item item = new Item(errorDataStorage,errorDataStorage); + items.add(item); + } + } + return items; + } +} +``` + +#### 服务层 +`ErrorDataStorageServiceImpl` 类实现了 `ErrorDataStorageService` 接口,提供了具体的业务逻辑。 + +```java +@Slf4j +@Service("errorDataStorageService") +public class ErrorDataStorageServiceImpl extends ServiceImpl implements ErrorDataStorageService { + @Override + public boolean testConnect(TestConnectionRequestParam param) { + // 测试连接逻辑 + } + + @Override + public long create(ErrorDataStorageCreate tenantCreate) throws DataVinesServerException { + // 创建错误数据存储逻辑 + } + + @Override + public int deleteById(long id) { + // 删除错误数据存储逻辑 + } + + @Override + public int update(ErrorDataStorageUpdate tenantUpdate) throws DataVinesServerException { + // 更新错误数据存储逻辑 + } + + @Override + public ErrorDataStorage getById(long id) { + // 获取错误数据存储逻辑 + } + + @Override + public List listByWorkspaceId(long workspaceId) { + // 列出工作区内的错误数据存储逻辑 + } + + @Override + public IPage getErrorDataStoragePage(ErrorDataStoragePageParam errorDataStoragePageParam) { + // 获取错误数据存储分页逻辑 + } + + @Override + public String getConfigJson(String type) { + // 获取配置 JSON 逻辑 + } +} +``` + +**节源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [ConfigBuilder.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java) +- [JdbcConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java) +- [MysqlConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConfigBuilder.java) +- [ErrorDataStorageController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/ErrorDataStorageController.java) +- [ErrorDataStorageServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/ErrorDataStorageServiceImpl.java) +- [ErrorDataStorageCreate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/storage/ErrorDataStorageCreate.java) +- [ErrorDataStorageUpdate.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/bo/storage/ErrorDataStorageUpdate.java) + +## 依赖分析 +DataVines 依赖于多个外部组件和库,以实现其功能。主要依赖包括: + +- **Java 运行环境**: JDK 8 +- **数据库**: MySQL、PostgreSQL +- **执行引擎**: Spark 2.4 +- **注册中心**: MySQL、PostgreSQL、ZooKeeper +- **通知服务**: 邮件、钉钉、飞书、企业微信 + +```mermaid +graph TB +subgraph "外部依赖" +Java[Java 运行环境] +MySQL[MySQL] +PostgreSQL[PostgreSQL] +Spark[Spark 2.4] +ZooKeeper[ZooKeeper] +Email[邮件] +DingTalk[钉钉] +FeiShu[飞书] +WeCom[企业微信] +end +subgraph "DataVines" +UI[用户界面] +API[API 服务器] +Auth[认证服务] +DB[(数据库)] +end +Java --> API +MySQL --> DB +PostgreSQL --> DB +Spark --> API +ZooKeeper --> API +Email --> API +DingTalk --> API +FeiShu --> API +WeCom --> API +``` + +**图源** +- [pom.xml](file://pom.xml) + +**节源** +- [pom.xml](file://pom.xml) + +## 性能考虑 +为了提高 DataVines 的性能,可以采取以下措施: + +- **水平扩展**: 通过增加 Server 节点来提高系统的处理能力。 +- **缓存**: 使用缓存机制减少数据库查询次数,提高响应速度。 +- **异步处理**: 将耗时的操作异步处理,避免阻塞主线程。 +- **优化查询**: 优化 SQL 查询语句,减少不必要的数据传输。 +- **资源管理**: 合理分配和管理资源,避免资源浪费。 + +## 故障排除指南 +在使用 DataVines 时,可能会遇到一些常见问题。以下是一些故障排除建议: + +- **连接问题**: 检查数据库连接配置是否正确,确保数据库服务正常运行。 +- **性能问题**: 监控系统性能,分析瓶颈,优化配置。 +- **数据质量问题**: 检查数据源配置,确保数据源连接正常,数据质量检查规则配置正确。 +- **日志问题**: 查看日志文件,定位问题原因,及时修复。 + +**节源** +- [server-logback.xml](file://datavines-server/src/main/resources/server-logback.xml) + +## 结论 +DataVines 是一个功能强大的数据质量服务平台,支持多种数据源、检查规则、执行模式和通知方式。通过合理的配置和优化,可以有效提高数据质量和系统性能。希望本文档能帮助您更好地理解和使用 DataVines。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\345\210\206\345\270\203\345\274\217\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\345\210\206\345\270\203\345\274\217\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256.md" new file mode 100644 index 00000000..7030024e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\345\210\206\345\270\203\345\274\217\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256.md" @@ -0,0 +1,134 @@ +# 分布式文件系统配置 + + +**本文档中引用的文件** +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) +- [HiveDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceClient.java) +- [common.properties](file://datavines-common\src\main\resources\common.properties) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java) +- [README.md](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\README.md) + + +## 目录 +1. [简介](#简介) +2. [HDFS集成配置](#hdfs集成配置) +3. [NameNode地址配置](#namenode地址配置) +4. [HDFS用户认证与Kerberos安全配置](#hdfs用户认证与kerberos安全配置) +5. [HDFS文件路径与权限配置](#hdfs文件路径与权限配置) +6. [副本策略配置](#副本策略配置) +7. [HDFS性能调优建议](#hdfs性能调优建议) +8. [HDFS连接测试与故障排查](#hdfs连接测试与故障排查) + +## 简介 +本文档详细说明了在DataVines平台中配置分布式文件系统(HDFS)的方法,包括Hadoop配置文件的集成、NameNode地址配置、HDFS用户认证、Kerberos安全配置等。同时,文档还解释了如何配置HDFS文件路径、文件权限和副本策略,并提供了HDFS性能调优建议,如块大小设置、读取缓冲区配置、并发连接数等。最后,文档包含了HDFS连接测试和故障排查指南。 + +## HDFS集成配置 +在DataVines平台中,HDFS的集成主要通过Hive连接器实现。Hive连接器支持通过JDBC连接到Hive服务,并通过HDFS存储数据。Hive连接器的配置主要涉及以下几个方面: + +1. **Hive元数据仓库目录**:通过`hive.metastore.warehouse.dir`参数配置Hive元数据仓库的HDFS路径。 +2. **Hive元数据服务地址**:通过`hive.metastore.uris`参数配置Hive元数据服务的Thrift地址。 +3. **HDFS库文件路径**:通过`livy.task.jar.lib.path`参数配置Livy任务所需的JAR文件在HDFS上的路径。 + +**Section sources** +- [README.md](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\README.md#L22) +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L107) + +## NameNode地址配置 +NameNode地址的配置主要通过Hive连接器的JDBC URL实现。在Hive连接器的配置中,JDBC URL通常包含NameNode的地址和端口。例如: + +``` +jdbc:hive2://:/default +``` + +其中,``是NameNode的主机名或IP地址,``是HiveServer2的端口。 + +**Section sources** +- [HiveDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceClient.java#L32) + +## HDFS用户认证与Kerberos安全配置 +DataVines平台支持通过Kerberos进行HDFS用户认证。Kerberos配置主要涉及以下几个方面: + +1. **Kerberos配置文件路径**:通过`krb5.conf`文件配置Kerberos的认证信息。 +2. **Keytab文件路径**:通过`keytab.file`参数配置用户的Keytab文件路径。 +3. **Kerberos主体**:通过`keytab.principal`参数配置用户的Kerberos主体。 + +Kerberos认证的初始化通过`KerberosUtils`类实现,该类提供了检查Kerberos配置、获取Keytab中的主体列表和初始化Kerberos认证的功能。 + +```mermaid +classDiagram +class KerberosUtils { ++static final String JAVA_SECURITY_KRB5_CONF ++static final String HADOOP_SECURITY_AUTHENTICATION ++static final String KERBEROS ++checkKerberosConfig(keytabPrincipal, keytabPath, krb5Config) boolean ++getPrincipalListFromKeytab(keytabPath) String[] ++initKerberos(keytabPrincipal, keytabPath, krb5Config) boolean +} +class HiveDataSourceClient { ++getConnection(baseJdbcDataSourceInfo) Connection ++getConnection(configMap, logger) Connection +} +KerberosUtils --> HiveDataSourceClient : "used by" +``` + +**Diagram sources** +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java#L30-L77) +- [HiveDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceClient.java#L30-L38) + +**Section sources** +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java#L30-L77) +- [HiveDataSourceClient.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveDataSourceClient.java#L30-L38) + +## HDFS文件路径与权限配置 +HDFS文件路径的配置主要通过`common.properties`文件中的相关参数实现。例如: + +- `local.tmp.workdir`:配置本地临时工作目录。 +- `local.data.dir`:配置本地数据目录。 +- `error.data.dir`:配置错误数据目录。 +- `validate.result.data.dir`:配置验证结果数据目录。 + +这些目录的配置可以影响HDFS上文件的存储路径和权限。 + +**Section sources** +- [common.properties](file://datavines-common\src\main\resources\common.properties#L65-L75) +- [CommonPropertyUtils.java](file://datavines-common\src\main\java\io\datavines\common\utils\CommonPropertyUtils.java#L65-L75) + +## 副本策略配置 +HDFS的副本策略配置主要通过Hadoop的`hdfs-site.xml`文件实现。在DataVines平台中,副本策略的配置可以通过环境变量或配置文件传递给Hadoop集群。副本策略的配置包括: + +- `dfs.replication`:配置文件的副本数。 +- `dfs.blocksize`:配置HDFS块的大小。 + +这些配置可以通过Livy任务的`conf`参数传递给Spark作业。 + +**Section sources** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L146-L151) + +## HDFS性能调优建议 +为了优化HDFS的性能,建议进行以下配置: + +1. **块大小设置**:根据数据大小和访问模式调整HDFS块大小。较大的块大小可以减少NameNode的元数据压力,但可能会增加小文件的存储开销。 +2. **读取缓冲区配置**:通过`io.file.buffer.size`参数配置HDFS读取缓冲区的大小,以提高读取性能。 +3. **并发连接数**:通过`dfs.client.max.block.acquire.threads`参数配置客户端获取块的最大线程数,以提高并发性能。 + +这些配置可以通过Livy任务的`conf`参数传递给Spark作业。 + +**Section sources** +- [LivyEngineExecutor.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-livy\datavines-engine-livy-executor\src\main\java\io\datavines\engine\livy\executor\LivyEngineExecutor.java#L146-L151) + +## HDFS连接测试与故障排查 +在配置HDFS连接后,建议进行连接测试以确保配置正确。连接测试可以通过以下步骤进行: + +1. **测试Hive连接**:使用Hive连接器的`testConnect`方法测试Hive连接。 +2. **检查Kerberos配置**:使用`KerberosUtils.checkKerberosConfig`方法检查Kerberos配置是否正确。 +3. **检查HDFS路径**:通过HDFS命令行工具检查HDFS路径是否存在且权限正确。 + +如果连接测试失败,可以参考以下故障排查步骤: + +1. **检查Kerberos日志**:查看Kerberos认证日志,确认认证是否成功。 +2. **检查HDFS日志**:查看HDFS日志,确认HDFS服务是否正常运行。 +3. **检查网络连接**:确认客户端与NameNode和DataNode之间的网络连接是否正常。 + +**Section sources** +- [HiveConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConnector.java#L54-L58) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java#L39-L49) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256.md" new file mode 100644 index 00000000..71db426e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256.md" @@ -0,0 +1,424 @@ +# 文件系统配置 + + +**本文档中引用的文件** +- [FileConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileConnectorFactory.java) +- [FileExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileExecutor.java) +- [FileParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileParameterConverter.java) +- [LocalFileSink.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-connector-file\src\main\java\io\datavines\engine\local\connector\LocalFileSink.java) +- [FileUtils.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-api\src\main\java\io\datavines\engine\local\api\utils\FileUtils.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) +- [submit_job_file_source.json](file://datavines-runner\src\main\resources\submit_job_file_source.json) +- [submit_job_file_storage.json](file://datavines-runner\src\main\resources\submit_job_file_storage.json) +- [HiveConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConfigBuilder.java) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) +- [common.properties](file://datavines-common\src\main\resources\common.properties) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +DataVines 是一个大数据质量检测平台,支持多种数据源的连接和验证。本文档重点介绍文件系统连接器的配置方法,包括本地文件系统、HDFS 和 S3 存储系统的配置。文档详细说明了文件路径格式、认证方式(如 AWS 凭证、Hadoop 配置)、支持的文件格式(CSV、JSON、Parquet 等)、压缩格式等。此外,还解释了如何配置文件监控、增量读取等高级特性,并提供性能调优建议,如批量读取、缓存策略、并发控制等。最后,说明了如何测试文件系统连接器的连通性和性能。 + +## 项目结构 +DataVines 项目采用模块化设计,主要分为以下几个部分: +- **datavines-connector**: 数据源连接器模块,包含各种数据源的连接器实现。 +- **datavines-engine**: 执行引擎模块,负责任务的执行和调度。 +- **datavines-common**: 公共工具和配置模块,提供通用的工具类和常量。 +- **datavines-server**: 服务器模块,提供 REST API 和 Web 界面。 +- **datavines-runner**: 任务运行器模块,负责启动和管理任务执行。 + +```mermaid +graph TB +subgraph "datavines-connector" +FileConnector[FileConnector] +HiveConnector[HiveConnector] +JdbcConnector[JdbcConnector] +end +subgraph "datavines-engine" +EngineExecutor[EngineExecutor] +LocalFileSink[LocalFileSink] +end +subgraph "datavines-common" +ConfigConstants[ConfigConstants] +FileUtils[FileUtils] +end +subgraph "datavines-server" +Server[Server] +end +subgraph "datavines-runner" +Runner[Runner] +end +FileConnector --> EngineExecutor +HiveConnector --> EngineExecutor +JdbcConnector --> EngineExecutor +EngineExecutor --> LocalFileSink +EngineExecutor --> Server +Runner --> EngineExecutor +ConfigConstants --> FileConnector +ConfigConstants --> HiveConnector +ConfigConstants --> JdbcConnector +FileUtils --> LocalFileSink +``` + +**图源** +- [FileConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileConnectorFactory.java) +- [LocalFileSink.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-connector-file\src\main\java\io\datavines\engine\local\connector\LocalFileSink.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) + +**节源** +- [FileConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileConnectorFactory.java) +- [LocalFileSink.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-connector-file\src\main\java\io\datavines\engine\local\connector\LocalFileSink.java) +- [ConfigConstants.java](file://datavines-common\src\main\java\io\datavines\common\ConfigConstants.java) + +## 核心组件 +### 文件连接器 +文件连接器(FileConnector)是 DataVines 中用于处理文件系统数据源的核心组件。它实现了 `Connector` 接口,提供了基本的连接和查询功能。文件连接器通过 `FileConnectorFactory` 工厂类创建,支持多种文件格式和认证方式。 + +```java +public class FileConnector implements Connector { + @Override + public List keyProperties() { + return Collections.emptyList(); + } +} +``` + +**节源** +- [FileConnector.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileConnector.java) + +### 文件执行器 +文件执行器(FileExecutor)负责执行文件系统的查询操作。它实现了 `Executor` 接口,提供了分页查询和单条记录查询的功能。文件执行器通过 `FileExecutor` 类实现,支持 CSV、JSON、Parquet 等多种文件格式。 + +```java +@Slf4j +public class FileExecutor implements Executor { + @Override + public ConnectorResponse queryForPage(ExecuteRequestParam param) throws Exception { + ConnectorResponse.ConnectorResponseBuilder builder = ConnectorResponse.builder(); + + int pageNumber = param.getPageNumber(); + int pageSize = param.getPageSize(); + + Map parameterMap = JSONUtils.toMap(param.getDataSourceParam(), String.class, String.class); + String dir = parameterMap.get("data_dir"); + String filePath = dir +"/" + param.getScript() ; + + if (FileUtils.isExist(filePath)) { + if (pageNumber < 1) { + pageNumber = 1; + } + + if (pageSize < 1) { + pageSize = 10; + } + + builder.result(readForPage(filePath, pageNumber, pageSize, parameterMap.get("column_separator"))); + } + + return builder.build(); + } + + @Override + public ConnectorResponse queryForOne(ExecuteRequestParam param) throws Exception { + ConnectorResponse.ConnectorResponseBuilder builder = ConnectorResponse.builder(); + + Map parameterMap = JSONUtils.toMap(param.getDataSourceParam(), String.class, String.class); + String dir = parameterMap.get("data_dir"); + String filePath = dir +"/" + param.getScript(); + builder.result(readForPage(filePath,1, 2, parameterMap.get("column_separator"))); + return builder.build(); + } +} +``` + +**节源** +- [FileExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileExecutor.java) + +### 文件参数转换器 +文件参数转换器(FileParameterConverter)负责将用户输入的参数转换为文件系统连接器所需的格式。它实现了 `ParameterConverter` 接口,支持多种参数类型和格式。 + +```java +public class FileParameterConverter implements ParameterConverter { + @Override + public Map converter(Map parameter) { + return parameter; + } +} +``` + +**节源** +- [FileParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileParameterConverter.java) + +## 架构概述 +DataVines 的文件系统连接器架构主要包括以下几个部分: +- **连接器工厂**:负责创建和管理连接器实例。 +- **连接器**:提供基本的连接和查询功能。 +- **执行器**:负责执行具体的查询操作。 +- **参数转换器**:负责将用户输入的参数转换为连接器所需的格式。 +- **响应转换器**:负责将查询结果转换为用户友好的格式。 + +```mermaid +classDiagram +class ConnectorFactory { ++String getCategory() ++Connector getConnector() ++ResponseConverter getResponseConverter() ++Dialect getDialect() ++ParameterConverter getConnectorParameterConverter() ++Executor getExecutor() ++TypeConverter getTypeConverter() ++ConfigBuilder getConfigBuilder() ++DataSourceClient getDataSourceClient() ++StatementSplitter getStatementSplitter() ++StatementParser getStatementParser() ++MetricScript getMetricScript() ++Boolean showInFrontend() +} +class Connector { ++List keyProperties() +} +class Executor { ++ConnectorResponse queryForPage(ExecuteRequestParam param) ++ConnectorResponse queryForOne(ExecuteRequestParam param) +} +class ParameterConverter { ++Map converter(Map parameter) +} +class ResponseConverter { +} +class Dialect { +} +class TypeConverter { +} +class ConfigBuilder { +} +class DataSourceClient { +} +class StatementSplitter { +} +class StatementParser { +} +class MetricScript { +} +ConnectorFactory --> Connector : "创建" +ConnectorFactory --> Executor : "创建" +ConnectorFactory --> ParameterConverter : "创建" +ConnectorFactory --> ResponseConverter : "创建" +ConnectorFactory --> Dialect : "创建" +ConnectorFactory --> TypeConverter : "创建" +ConnectorFactory --> ConfigBuilder : "创建" +ConnectorFactory --> DataSourceClient : "创建" +ConnectorFactory --> StatementSplitter : "创建" +ConnectorFactory --> StatementParser : "创建" +ConnectorFactory --> MetricScript : "创建" +``` + +**图源** +- [FileConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileConnectorFactory.java) + +**节源** +- [FileConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileConnectorFactory.java) + +## 详细组件分析 +### 文件连接器工厂 +文件连接器工厂(FileConnectorFactory)是文件连接器的创建工厂,负责创建和管理文件连接器实例。它实现了 `ConnectorFactory` 接口,提供了创建连接器、执行器、参数转换器等组件的方法。 + +```java +public class FileConnectorFactory implements ConnectorFactory { + @Override + public String getCategory() { + return "file"; + } + + @Override + public Connector getConnector() { + return new FileConnector(); + } + + @Override + public ResponseConverter getResponseConverter() { + return new FileResponseConverter(); + } + + @Override + public Dialect getDialect() { + return new FileDialect(); + } + + @Override + public ParameterConverter getConnectorParameterConverter() { + return new FileParameterConverter(); + } + + @Override + public Executor getExecutor() { + return new FileExecutor(); + } + + @Override + public TypeConverter getTypeConverter() { + return new FileTypeConverter(); + } + + @Override + public ConfigBuilder getConfigBuilder() { + return null; + } + + @Override + public DataSourceClient getDataSourceClient() { + return null; + } + + @Override + public StatementSplitter getStatementSplitter() { + return null; + } + + @Override + public StatementParser getStatementParser() { + return null; + } + + @Override + public MetricScript getMetricScript() { + return null; + } + + @Override + public Boolean showInFrontend() { + return false; + } +} +``` + +**节源** +- [FileConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileConnectorFactory.java) + +### 文件执行器 +文件执行器(FileExecutor)负责执行文件系统的查询操作。它实现了 `Executor` 接口,提供了分页查询和单条记录查询的功能。文件执行器通过 `FileExecutor` 类实现,支持 CSV、JSON、Parquet 等多种文件格式。 + +```java +@Slf4j +public class FileExecutor implements Executor { + @Override + public ConnectorResponse queryForPage(ExecuteRequestParam param) throws Exception { + ConnectorResponse.ConnectorResponseBuilder builder = ConnectorResponse.builder(); + + int pageNumber = param.getPageNumber(); + int pageSize = param.getPageSize(); + + Map parameterMap = JSONUtils.toMap(param.getDataSourceParam(), String.class, String.class); + String dir = parameterMap.get("data_dir"); + String filePath = dir +"/" + param.getScript() ; + + if (FileUtils.isExist(filePath)) { + if (pageNumber < 1) { + pageNumber = 1; + } + + if (pageSize < 1) { + pageSize = 10; + } + + builder.result(readForPage(filePath, pageNumber, pageSize, parameterMap.get("column_separator"))); + } + + return builder.build(); + } + + @Override + public ConnectorResponse queryForOne(ExecuteRequestParam param) throws Exception { + ConnectorResponse.ConnectorResponseBuilder builder = ConnectorResponse.builder(); + + Map parameterMap = JSONUtils.toMap(param.getDataSourceParam(), String.class, String.class); + String dir = parameterMap.get("data_dir"); + String filePath = dir +"/" + param.getScript(); + builder.result(readForPage(filePath,1, 2, parameterMap.get("column_separator"))); + return builder.build(); + } +} +``` + +**节源** +- [FileExecutor.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileExecutor.java) + +### 文件参数转换器 +文件参数转换器(FileParameterConverter)负责将用户输入的参数转换为文件系统连接器所需的格式。它实现了 `ParameterConverter` 接口,支持多种参数类型和格式。 + +```java +public class FileParameterConverter implements ParameterConverter { + @Override + public Map converter(Map parameter) { + return parameter; + } +} +``` + +**节源** +- [FileParameterConverter.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileParameterConverter.java) + +## 依赖分析 +DataVines 的文件系统连接器依赖于多个模块和库,主要包括: +- **datavines-common**: 提供通用的工具类和常量。 +- **datavines-connector-api**: 提供连接器接口和基类。 +- **datavines-engine-api**: 提供执行引擎接口和基类。 +- **Hadoop**: 用于 HDFS 文件系统的访问。 +- **AWS SDK**: 用于 S3 文件系统的访问。 + +```mermaid +graph TD +FileConnector --> datavines-common +FileConnector --> datavines-connector-api +FileExecutor --> datavines-common +FileExecutor --> datavines-connector-api +FileParameterConverter --> datavines-common +FileParameterConverter --> datavines-connector-api +LocalFileSink --> datavines-common +LocalFileSink --> datavines-engine-api +HiveConnector --> Hadoop +S3Connector --> AWS-SDK +``` + +**图源** +- [FileConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileConnectorFactory.java) +- [LocalFileSink.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-connector-file\src\main\java\io\datavines\engine\local\connector\LocalFileSink.java) +- [HiveConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConfigBuilder.java) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) + +**节源** +- [FileConnectorFactory.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-file\src\main\java\io\datavines\connector\plugin\FileConnectorFactory.java) +- [LocalFileSink.java](file://datavines-engine\datavines-engine-plugins\datavines-engine-local\datavines-engine-local-connector-file\src\main\java\io\datavines\engine\local\connector\LocalFileSink.java) +- [HiveConfigBuilder.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\HiveConfigBuilder.java) +- [KerberosUtils.java](file://datavines-connector\datavines-connector-plugins\datavines-connector-hive\src\main\java\io\datavines\connector\plugin\KerberosUtils.java) + +## 性能考虑 +为了提高文件系统连接器的性能,可以采取以下措施: +- **批量读取**:通过设置合适的批量大小,减少 I/O 操作次数。 +- **缓存策略**:使用缓存机制,减少重复读取文件的开销。 +- **并发控制**:通过多线程或异步操作,提高文件读取的并发度。 +- **压缩格式**:使用高效的压缩格式,减少文件传输和存储的开销。 + +## 故障排除指南 +### 连接问题 +- **检查文件路径**:确保文件路径正确无误。 +- **检查权限**:确保有足够的权限访问文件。 +- **检查网络**:对于远程文件系统,确保网络连接正常。 + +### 性能问题 +- **检查批量大小**:调整批量大小,找到最佳性能点。 +- **检查缓存**:确保缓存机制正常工作。 +- **检查并发度**:调整并发度,避免资源竞争。 + +## 结论 +DataVines 的文件系统连接器提供了强大的文件系统访问能力,支持多种文件格式和认证方式。通过合理的配置和优化,可以显著提高文件读取的性能和可靠性。本文档详细介绍了文件系统连接器的配置方法和最佳实践,希望对用户有所帮助。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\346\234\254\345\234\260\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\346\234\254\345\234\260\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256.md" new file mode 100644 index 00000000..702d39f1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256/\346\234\254\345\234\260\346\226\207\344\273\266\347\263\273\347\273\237\351\205\215\347\275\256.md" @@ -0,0 +1,152 @@ +# 本地文件系统配置 + + +**本文档中引用的文件** +- [FileConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnector.java) +- [FileConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnectorFactory.java) +- [FileExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileExecutor.java) +- [FileDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileDialect.java) +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java) +- [LocalFileSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSink.java) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java) +- [submit_job_file_source.json](file://datavines-runner/src/main/resources/submit_job_file_source.json) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细说明了如何配置本地文件系统连接器,包括本地文件路径、文件权限、文件格式(CSV、JSON、Parquet等)和压缩格式(GZIP、SNAPPY等)的配置。文档还解释了文件读取模式、编码设置、分隔符配置等参数,并提供了配置示例和最佳实践,包括如何处理大文件、文件锁定机制、文件监控等。此外,文档还说明了如何测试本地文件系统连接器的连通性和性能。 + +## 项目结构 +本项目采用模块化设计,主要分为以下几个部分: +- `datavines-connector`: 包含各种数据源连接器的实现,包括本地文件系统连接器。 +- `datavines-engine`: 包含执行引擎的实现,支持本地、Spark、Flink等执行模式。 +- `datavines-common`: 包含通用工具类和常量定义。 +- `datavines-runner`: 包含作业提交和执行的入口。 + +**本地文件系统连接器相关文件路径:** +- `datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/`: 本地文件连接器的核心实现。 +- `datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/`: 本地文件源和接收器的实现。 + +**Section sources** +- [FileConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnector.java#L1-L31) +- [FileConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnectorFactory.java#L1-L88) + +## 核心组件 +本地文件系统连接器的核心组件包括: +- `FileConnector`: 实现了`Connector`接口,用于连接本地文件系统。 +- `FileExecutor`: 负责执行文件读取操作,支持分页查询。 +- `LocalFileSource`: 本地文件源,用于从本地文件系统读取数据。 +- `LocalFileSink`: 本地文件接收器,用于将数据写入本地文件系统。 + +**Section sources** +- [FileExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileExecutor.java#L1-L163) +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java#L1-L144) +- [LocalFileSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSink.java#L1-L161) + +## 架构概述 +本地文件系统连接器的架构如下图所示: + +```mermaid +graph TD +A[客户端] --> B[FileConnector] +B --> C[FileExecutor] +C --> D[LocalFileSource] +C --> E[LocalFileSink] +D --> F[本地文件系统] +E --> F[本地文件系统] +``` + +**Diagram sources** +- [FileConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnector.java#L1-L31) +- [FileExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileExecutor.java#L1-L163) +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java#L1-L144) +- [LocalFileSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSink.java#L1-L161) + +## 详细组件分析 + +### FileConnector 分析 +`FileConnector`是本地文件系统连接器的核心类,实现了`Connector`接口。它通过`FileConnectorFactory`创建,并提供了连接本地文件系统的能力。 + +**Section sources** +- [FileConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnector.java#L1-L31) +- [FileConnectorFactory.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnectorFactory.java#L1-L88) + +### FileExecutor 分析 +`FileExecutor`负责执行文件读取操作,支持分页查询。它通过`readForPage`方法读取指定页码和页大小的数据,并返回包含结果列表和列信息的`ListWithQueryColumn`对象。 + +```mermaid +sequenceDiagram +participant Client +participant FileExecutor +participant LocalFileSource +Client->>FileExecutor : queryForPage() +FileExecutor->>LocalFileSource : readForPage() +LocalFileSource-->>FileExecutor : ListWithQueryColumn +FileExecutor-->>Client : ConnectorResponse +``` + +**Diagram sources** +- [FileExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileExecutor.java#L1-L163) +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java#L1-L144) + +### LocalFileSource 分析 +`LocalFileSource`是本地文件源,用于从本地文件系统读取数据。它通过`getConnectionItem`方法创建连接,并使用H2内存数据库将CSV文件加载到内存中进行查询。 + +**Section sources** +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java#L1-L144) + +### LocalFileSink 分析 +`LocalFileSink`是本地文件接收器,用于将数据写入本地文件系统。它支持将验证结果和错误数据写入指定目录。 + +**Section sources** +- [LocalFileSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSink.java#L1-L161) + +## 依赖分析 +本地文件系统连接器依赖于以下组件: +- `H2`: 用于在内存中创建临时表以查询CSV文件。 +- `Druid`: 用于数据库连接池管理。 +- `CommonPropertyUtils`: 用于读取配置属性。 + +```mermaid +graph TD +A[FileConnector] --> B[H2] +A --> C[Druid] +A --> D[CommonPropertyUtils] +``` + +**Diagram sources** +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java#L1-L144) +- [LocalFileSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSink.java#L1-L161) +- [CommonPropertyUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/CommonPropertyUtils.java#L1-L351) + +## 性能考虑 +- **大文件处理**: 本地文件系统连接器对文件大小有限制,默认最大文件长度为10MB。可以通过配置`file.max.length`属性来调整此限制。 +- **文件锁定**: 使用ZooKeeper进行文件锁定,确保在分布式环境中文件的独占访问。 +- **文件监控**: 可以通过配置文件监控来检测文件的变化并触发相应的操作。 + +**Section sources** +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java#L100-L109) +- [ZooKeeperClient.java](file://datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java#L206-L224) + +## 故障排除指南 +- **文件路径错误**: 确保配置的文件路径正确且文件存在。 +- **文件格式错误**: 确保文件格式符合预期,特别是CSV文件的分隔符和编码。 +- **权限问题**: 确保应用程序有读取和写入文件的权限。 +- **大文件处理失败**: 检查文件大小是否超过配置的最大文件长度。 + +**Section sources** +- [LocalFileSource.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSource.java#L100-L109) +- [LocalFileSink.java](file://datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-connector-file/src/main/java/io/datavines/engine/local/connector/LocalFileSink.java#L120-L160) + +## 结论 +本文档详细介绍了本地文件系统连接器的配置和使用方法。通过合理配置文件路径、格式、权限等参数,可以高效地处理本地文件数据。同时,通过最佳实践和故障排除指南,可以确保系统的稳定性和性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256.md" new file mode 100644 index 00000000..50f188fb --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256/\350\277\236\346\216\245\345\231\250\351\205\215\347\275\256.md" @@ -0,0 +1,626 @@ +# 连接器配置 + + +**本文档中引用的文件** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [JdbcDialect.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java) +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) +- [JdbcConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcConnectionInfo.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java) +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java) +- [DorisParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java) +- [DorisConfigBuilder.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java) + + +## 更新摘要 +**变更内容** +- 新增Doris连接器多目录(catalog)配置参数说明 +- 添加CATALOG参数的使用方法和默认目录(internal)配置 +- 更新JDBC连接器配置章节,包含Doris特有的目录切换机制 +- 增加Doris连接器的连接测试和性能优化建议 + +## 目录 +1. [简介](#简介) +2. [连接器架构](#连接器架构) +3. [核心组件](#核心组件) +4. [数据源配置](#数据源配置) +5. [JDBC连接器配置](#jdbc连接器配置) +6. [高级连接选项](#高级连接选项) +7. [连接池配置](#连接池配置) +8. [连接测试](#连接测试) +9. [性能调优建议](#性能调优建议) +10. [自定义连接器开发](#自定义连接器开发) + +## 简介 + +DataVines支持多种数据源连接器,包括MySQL、PostgreSQL、Oracle、SQL Server、Hive、Spark、Flink等。本文档详细说明了这些连接器的配置方法,包括连接参数、认证方式、连接池配置、超时设置等。同时,文档还解释了如何配置JDBC连接字符串、Kerberos认证等高级选项,并提供了连接器性能调优建议,如连接复用、批量操作等。最后,文档说明了如何开发和集成自定义连接器,以及如何测试连接器的连通性。 + +**新增** DataVines现已支持Doris连接器,该连接器具有独特的多目录(catalog)配置能力,允许用户在连接时指定不同的数据目录,并提供默认的internal目录配置。 + +## 连接器架构 + +DataVines的连接器架构基于插件化设计,通过统一的接口实现不同数据源的连接和操作。核心架构包括连接器(Connector)、数据源客户端(DataSourceClient)、执行器(Executor)和方言(Dialect)四个主要组件。 + +```mermaid +graph TD +Connector[连接器 Connector] --> DataSourceClient[数据源客户端 DataSourceClient] +Connector --> Executor[执行器 Executor] +Connector --> Dialect[方言 Dialect] +DataSourceClient --> JdbcDataSourceManager[连接池管理器 JdbcDataSourceManager] +Executor --> DataSourceClient +Dialect --> SQL[SQL生成] +DorisConnector[Doris连接器] --> MysqlConnector[MySQL连接器基类] +DorisConnector --> DorisDataSourceInfo[Doris数据源信息] +DorisConnector --> DorisParameterConverter[Doris参数转换器] +``` + +**图表来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java) + +## 核心组件 + +DataVines连接器的核心组件包括连接器接口、数据源客户端、执行器和方言。这些组件共同协作,实现对不同数据源的统一访问和操作。 + +**组件来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) + +### 连接器接口 + +连接器接口(Connector)定义了数据源连接的基本操作,包括获取数据库、表、列信息,以及测试连接等。 + +```mermaid +classDiagram +class Connector { ++getDatabases(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++getPartitions(param) ConnectorResponse ++testConnect(param) ConnectorResponse ++keyProperties() String[] +} +``` + +**图表来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) + +### 数据源客户端 + +数据源客户端(DataSourceClient)负责管理数据源连接,提供获取数据源和连接的方法。 + +```mermaid +classDiagram +class DataSourceClient { ++getDataSource(info) DataSource ++getDataSource(configMap) DataSource ++getDataSource(properties) DataSource ++getConnection(info) Connection ++getConnection(configMap) Connection ++getConnection(configMap, logger) Connection ++getConnection(properties) Connection ++getJdbcTemplate(info) JdbcTemplate +} +``` + +**图表来源** +- [DataSourceClient.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java) + +### 执行器 + +执行器(Executor)负责执行SQL脚本和查询操作。 + +```mermaid +classDiagram +class Executor { ++queryForPage(param) ConnectorResponse ++queryForList(param) ConnectorResponse ++queryForOne(param) ConnectorResponse ++deleteData(param) ConnectorResponse +} +``` + +**图表来源** +- [Executor.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java) + +### 方言 + +方言(Dialect)定义了特定数据库的SQL语法和特性。 + +```mermaid +classDiagram +class Dialect { ++getDriver() String ++getColumnPrefix() String ++getColumnSuffix() String ++getDialectKeyMap() Map~String,String~ ++getExcludeDatabases() String[] ++getFullQualifiedTableName(database, schema, table, needQuote) String ++invalidateItemCanOutput() boolean ++invalidateItemCanOutputToSelf() boolean ++supportToBeErrorDataStorage() boolean ++getJDBCType(dataType) String ++getDataType(jdbcType) DataType ++quoteIdentifier(entity) String ++getQuoteIdentifier() String ++getTableExistsQuery(table) String ++getSchemaQuery(table) String ++getCountQuery(table) String ++getSelectQuery(table) String ++getCreateTableAsSelectStatement(srcTable, targetDatabase, targetTable) String ++getCreateTableAsSelectStatementFromSql(srcTable, targetDatabase, targetTable) String ++getCreateTableStatement(table, fields, typeConverter) String ++getInsertAsSelectStatement(srcTable, targetDatabase, targetTable) String ++getInsertAsSelectStatementFromSql(srcTable, targetDatabase, targetTable) String ++getErrorDataScript(configMap) String ++getValidateResultDataScript(configMap) String ++getPageFromResultSet(sourceConnectionStatement, rs, sourceTable, start, end) ResultList +} +``` + +**图表来源** +- [Dialect.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java) + +## 数据源配置 + +DataVines支持多种数据源的配置,每种数据源都有其特定的配置参数。 + +### 配置参数 + +所有数据源都支持以下基本配置参数: + +- **host**: 数据源地址 +- **port**: 端口号 +- **database**: 数据库名称 +- **user**: 用户名 +- **password**: 密码 +- **properties**: 连接属性 + +**新增** **catalog**: 目录类型(仅Doris连接器支持) + +```mermaid +flowchart TD +Start([开始]) --> HostCheck{"host是否配置?"} +HostCheck --> |是| PortCheck{"port是否配置?"} +HostCheck --> |否| Error[缺少host配置] +PortCheck --> |是| DatabaseCheck{"database是否配置?"} +PortCheck --> |否| Error +DatabaseCheck --> |是| CatalogCheck{"catalog是否配置?"} +DatabaseCheck --> |否| UserCheck{"user是否配置?"} +CatalogCheck --> |是| UserCheck +CatalogCheck --> |否| UserCheck +UserCheck --> |是| PasswordCheck{"password是否配置?"} +UserCheck --> |否| Error +PasswordCheck --> |是| Success[配置成功] +PasswordCheck --> |否| Warning[警告: 无密码配置] +Error --> End([结束]) +Warning --> End +Success --> End +``` + +**图表来源** +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcConnectionInfo.java) +- [ConfigConstants.java](file://datavines-common/src/main/java/io/datavines/common/ConfigConstants.java) + +## JDBC连接器配置 + +JDBC连接器是DataVines中最常用的连接器类型,支持多种关系型数据库。 + +### MySQL连接器 + +MySQL连接器通过JDBC驱动连接MySQL数据库。 + +```mermaid +classDiagram +class MysqlConnector { ++getDatasourceInfo(param) BaseJdbcDataSourceInfo ++getMetadataDatabases(connection) ResultSet +} +MysqlConnector --> JdbcConnector : 继承 +MysqlConnector --> MysqlDataSourceInfo : 使用 +``` + +**图表来源** +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +### PostgreSQL连接器 + +PostgreSQL连接器支持PostgreSQL数据库的连接和操作。 + +```mermaid +classDiagram +class PostgreSqlConnector { ++getDatasourceInfo(param) BaseJdbcDataSourceInfo ++getMetadataDatabases(connection) ResultSet ++getMetadataTables(metaData, catalog, schema) ResultSet +} +PostgreSqlConnector --> JdbcConnector : 继承 +PostgreSqlConnector --> PostgreSqlDataSourceInfo : 使用 +``` + +**图表来源** +- [PostgreSqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +### **新增** Doris连接器 + +Doris连接器支持Apache Doris数据库的连接和操作,具有独特的多目录(catalog)配置能力。 + +```mermaid +classDiagram +class DorisConnector { ++DORIS_DEFAULT_CATALOG : String ++getDatasourceInfo(param) BaseJdbcDataSourceInfo ++testConnect(param) ConnectorResponse ++getConnection(dataSourceParam, paramMap) Connection ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse +-switchCatalog(connection, catalogName) void +} +DorisConnector --> MysqlConnector : 继承 +DorisConnector --> DorisDataSourceInfo : 使用 +DorisConnector --> DorisParameterConverter : 使用 +DorisConnector --> DorisConfigBuilder : 使用 +``` + +**图表来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java) +- [MysqlConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java) + +#### **新增** Doris连接器配置参数 + +Doris连接器支持以下配置参数: + +- **host**: Doris服务器地址 +- **port**: 端口号(默认:9030) +- **catalog**: 目录类型(可选,默认:internal) +- **database**: 数据库名称 +- **user**: 用户名 +- **password**: 密码 +- **properties**: 连接属性 + +**新增** **CATALOG参数使用方法**: + +1. **指定目录类型**:在连接参数中设置`catalog`字段 +2. **默认目录**:未指定时自动使用`internal`目录 +3. **目录切换**:连接建立后自动执行`SWITCH`命令切换到指定目录 + +**新增** **目录切换机制**: + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant DorisConnector as Doris连接器 +participant Connection as 数据库连接 +participant Doris as Doris服务器 +Client->>DorisConnector : getConnection(dataSourceParam, paramMap) +DorisConnector->>DorisConnector : 获取catalog参数 +alt 指定了catalog +DorisConnector->>Connection : 建立数据库连接 +DorisConnector->>Doris : 执行SWITCH [catalog] +Doris-->>DorisConnector : 切换成功 +else 未指定catalog +DorisConnector->>Connection : 建立数据库连接 +DorisConnector->>Doris : 执行SWITCH internal +Doris-->>DorisConnector : 切换成功 +end +DorisConnector-->>Client : 返回连接 +``` + +**图表来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java) + +#### **新增** Doris连接器URL构建 + +Doris连接器根据是否指定catalog动态构建JDBC URL: + +```mermaid +flowchart TD +Start([开始]) --> CheckCatalog{"是否指定catalog?"} +CheckCatalog --> |是| BuildCatalogUrl[构建URL: jdbc:mysql://host:port/catalog.database] +CheckCatalog --> |否| CheckDatabase{"是否指定database?"} +BuildCatalogUrl --> End([结束]) +CheckDatabase --> |是| BuildDatabaseUrl[构建URL: jdbc:mysql://host:port/database] +CheckDatabase --> |否| BuildDefaultUrl[构建URL: jdbc:mysql://host:port] +BuildDatabaseUrl --> End +BuildDefaultUrl --> End +``` + +**图表来源** +- [DorisParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java) +- [DorisDataSourceInfo.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java) + +## 高级连接选项 + +DataVines支持多种高级连接选项,包括JDBC连接字符串配置和Kerberos认证。 + +### JDBC连接字符串 + +JDBC连接字符串的配置遵循标准的JDBC格式。 + +```mermaid +flowchart TD +Start([开始]) --> Protocol{"协议类型?"} +Protocol --> |mysql| MysqlFormat["jdbc:mysql://host:port/database?properties"] +Protocol --> |postgresql| PostgreSqlFormat["jdbc:postgresql://host:port/database?properties"] +Protocol --> |oracle| OracleFormat["jdbc:oracle:thin:@host:port:database"] +Protocol --> |sqlserver| SqlServerFormat["jdbc:sqlserver://host:port;databaseName=database"] +Protocol --> |doris| DorisFormat["jdbc:mysql://host:port/[catalog.]database?properties"] +MysqlFormat --> End([结束]) +PostgreSqlFormat --> End +OracleFormat --> End +SqlServerFormat --> End +DorisFormat --> End +``` + +**图表来源** +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) +- [JdbcConnectionInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcConnectionInfo.java) +- [DorisParameterConverter.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java) + +### Kerberos认证 + +Hive连接器支持Kerberos认证,需要配置相关参数。 + +```mermaid +sequenceDiagram +participant User as 用户 +participant HiveConnector as Hive连接器 +participant Kerberos as Kerberos服务 +User->>HiveConnector : 提交连接参数 +HiveConnector->>HiveConnector : 检查Kerberos配置 +alt 配置有效 +HiveConnector->>Kerberos : 初始化Kerberos +Kerberos-->>HiveConnector : 认证成功 +HiveConnector->>HiveConnector : 加载驱动类 +HiveConnector->>HiveConnector : 建立JDBC连接 +HiveConnector-->>User : 连接成功 +else 配置无效 +HiveConnector-->>User : 认证失败 +end +``` + +**图表来源** +- [HiveConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java) + +## 连接池配置 + +DataVines使用HikariCP作为默认的连接池实现,提供高效的连接管理。 + +### 连接池管理 + +连接池管理器负责创建和管理数据库连接。 + +```mermaid +classDiagram +class JdbcDataSourceManager { +-dataSourceMap : ConcurrentHashMap~String, HikariDataSource~ ++getDataSource(info) DataSource ++getDataSource(configMap) DataSource ++getDataSource(properties) DataSource ++close() void +-getUniqueKey(configMap) String +} +class HikariConfig { ++setJdbcUrl(url) void ++setUsername(username) void ++setPassword(password) void ++setDriverClassName(driver) void ++setMaximumPoolSize(size) void +} +JdbcDataSourceManager --> HikariConfig : 创建 +HikariConfig --> HikariDataSource : 实例化 +``` + +**图表来源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +### 连接池参数 + +连接池支持以下主要参数配置: + +- **maximumPoolSize**: 最大连接数,默认为10 +- **connectionTimeout**: 连接超时时间 +- **idleTimeout**: 空闲超时时间 +- **maxLifetime**: 连接最大生命周期 + +```mermaid +flowchart TD +Start([开始]) --> CreateConfig[创建HikariConfig] +CreateConfig --> SetUrl[设置JDBC URL] +SetUrl --> SetUser[设置用户名] +SetUser --> SetPassword[设置密码] +SetPassword --> SetDriver[设置驱动类] +SetDriver --> SetPoolSize[设置最大连接数] +SetPoolSize --> CreateDataSource[创建HikariDataSource] +CreateDataSource --> Store[存储到dataSourceMap] +Store --> End([结束]) +``` + +**图表来源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +## 连接测试 + +DataVines提供了连接测试功能,用于验证数据源连接的可用性。 + +### 连接测试流程 + +连接测试通过创建临时连接来验证连接参数的正确性。 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Connector as 连接器 +participant DriverManager as DriverManager +Client->>Connector : testConnect(param) +Connector->>Connector : 解析连接参数 +Connector->>Connector : 获取数据源信息 +Connector->>Connector : 加载驱动类 +Connector->>DriverManager : getConnection(url, user, password) +DriverManager-->>Connector : Connection +alt 连接成功 +Connector->>Connector : 关闭连接 +Connector-->>Client : 测试成功 +else 连接失败 +Connector-->>Client : 测试失败 +end +``` + +**图表来源** +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) +- [BaseJdbcDataSourceInfo.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java) + +**新增** **Doris连接器连接测试**: + +Doris连接器的连接测试流程与标准JDBC连接器类似,但会检查目录切换功能: + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant DorisConnector as Doris连接器 +participant DriverManager as DriverManager +participant Doris as Doris服务器 +Client->>DorisConnector : testConnect(param) +DorisConnector->>DorisConnector : 解析连接参数 +DorisConnector->>DorisConnector : 获取数据源信息 +DorisConnector->>DorisConnector : 加载驱动类 +DorisConnector->>DriverManager : getConnection(url, user, password) +DriverManager-->>DorisConnector : Connection +alt 连接成功 +DorisConnector->>Doris : 执行SWITCH命令 +Doris-->>DorisConnector : 切换成功 +DorisConnector->>DorisConnector : 关闭连接 +DorisConnector-->>Client : 测试成功 +else 连接失败 +DorisConnector-->>Client : 测试失败 +end +``` + +**图表来源** +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java) + +## 性能调优建议 + +为了提高连接器的性能,建议采用以下调优策略。 + +### 连接复用 + +通过连接池实现连接复用,避免频繁创建和销毁连接。 + +```mermaid +flowchart TD +Start([开始]) --> CheckPool{"连接池中有可用连接?"} +CheckPool --> |是| UseConnection[使用池中连接] +CheckPool --> |否| CreateConnection[创建新连接] +CreateConnection --> AddToPool[添加到连接池] +AddToPool --> UseConnection +UseConnection --> ExecuteQuery[执行查询] +ExecuteQuery --> ReturnConnection[归还连接到池] +ReturnConnection --> End([结束]) +``` + +**图表来源** +- [JdbcDataSourceManager.java](file://datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java) + +### 批量操作 + +对于大量数据操作,建议使用批量处理来提高效率。 + +```mermaid +flowchart TD +Start([开始]) --> PrepareBatch[准备批量操作] +PrepareBatch --> AddOperations[添加多个操作] +AddOperations --> ExecuteBatch[执行批量操作] +ExecuteBatch --> ProcessResults[处理结果] +ProcessResults --> End([结束]) +``` + +**图表来源** +- [BaseJdbcExecutor.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java) + +**新增** **Doris连接器性能优化建议**: + +1. **目录预切换**:在连接建立时自动切换到目标目录,避免后续查询中的目录切换开销 +2. **连接池优化**:为Doris连接器配置合适的连接池大小,考虑到目录切换的额外开销 +3. **批量查询**:利用Doris的批量查询能力,减少网络往返次数 +4. **索引优化**:合理使用Doris的分区和索引机制,提高查询性能 + +## 自定义连接器开发 + +DataVines支持开发自定义连接器,以支持新的数据源类型。 + +### 开发步骤 + +开发自定义连接器需要实现核心接口并注册为插件。 + +```mermaid +flowchart TD +Start([开始]) --> ImplementInterface[实现Connector接口] +ImplementInterface --> ExtendBase[继承基础类] +ExtendBase --> ImplementMethods[实现必要方法] +ImplementMethods --> AddDialect[添加方言支持] +AddDialect --> RegisterPlugin[注册为插件] +RegisterPlugin --> Test[测试连接器] +Test --> Deploy[部署到系统] +Deploy --> End([结束]) +``` + +**图表来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [JdbcConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java) + +### 接口实现 + +自定义连接器需要实现以下核心方法: + +- **getDatabases**: 获取数据库列表 +- **getTables**: 获取表列表 +- **getColumns**: 获取列信息 +- **testConnect**: 测试连接 +- **keyProperties**: 返回关键配置属性 + +**新增** **Doris连接器开发要点**: + +1. **继承关系**:Doris连接器继承自MysqlConnector,复用MySQL的大部分功能 +2. **目录支持**:实现CATALOG参数解析和目录切换逻辑 +3. **URL构建**:根据是否指定catalog动态构建JDBC URL +4. **默认目录**:设置internal为默认目录类型 +5. **连接测试**:在连接测试中验证目录切换功能 + +```mermaid +classDiagram +class CustomConnector { ++getDatabases(param) ConnectorResponse ++getTables(param) ConnectorResponse ++getColumns(param) ConnectorResponse ++testConnect(param) ConnectorResponse ++keyProperties() String[] +} +CustomConnector --> Connector : 实现 +DorisConnector --> MysqlConnector : 继承 +DorisConnector --> DorisDataSourceInfo : 使用 +DorisConnector --> DorisParameterConverter : 使用 +``` + +**图表来源** +- [Connector.java](file://datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java) +- [DorisConnector.java](file://datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/SLA\345\221\212\350\255\246\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/SLA\345\221\212\350\255\246\351\205\215\347\275\256.md" new file mode 100644 index 00000000..f190354f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/SLA\345\221\212\350\255\246\351\205\215\347\275\256.md" @@ -0,0 +1,414 @@ +# SLA告警配置 + + +**本文档引用文件** +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaSenderMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaSenderMessage.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java) +- [SlaConfigVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/SlaConfigVO.java) +- [SlaNotificationServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaNotificationServiceImpl.java) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) +- [LarkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java) +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java) + + +## 目录 +1. [SLA告警配置概述](#sla告警配置概述) +2. [SLA阈值与告警级别配置](#sla阈值与告警级别配置) +3. [多条件组合告警配置](#多条件组合告警配置) +4. [告警抑制与升级机制](#告警抑制与升级机制) +5. [通知渠道绑定与优先级设置](#通知渠道绑定与优先级设置) +6. [重复通知间隔与静默期配置](#重复通知间隔与静默期配置) +7. [SLA告警测试方法](#sla告警测试方法) +8. [监控看板集成方案](#监控看板集成方案) +9. [NotificationManager协调机制](#notificationmanager协调机制) +10. [配置示例与最佳实践](#配置示例与最佳实践) + +## SLA告警配置概述 + +DataVines中的SLA(服务等级协议)告警系统提供了一套完整的数据质量监控和通知机制,用于确保数据处理作业符合预定义的服务水平要求。该系统通过灵活的配置选项,支持多种告警策略和通知渠道,能够满足不同场景下的监控需求。 + +SLA告警系统的核心组件包括告警规则定义、阈值判断、通知渠道管理和告警结果处理。系统在数据质量检查失败时触发告警流程,通过NotificationManager协调多个通知插件,将告警信息发送给指定的接收者。 + +**本节来源** +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java#L28-L36) +- [SlaConfigVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/SlaConfigVO.java#L26-L33) + +## SLA阈值与告警级别配置 + +SLA阈值配置是告警系统的基础,决定了何时触发告警。在DataVines中,阈值配置与具体的度量指标(Metric)相关联,通过比较实际值与预期值来判断是否违反SLA。 + +告警级别通过不同的通知渠道和接收者来体现。系统支持配置多个级别的告警,例如: +- **警告级别**:通过邮件通知相关开发人员 +- **严重级别**:通过钉钉、飞书等即时通讯工具通知值班团队 +- **紧急级别**:通过企业微信机器人通知整个运维团队 + +阈值配置通常包含以下要素: +- **比较操作符**:支持大于、小于、等于、不等于等操作 +- **阈值数值**:具体的数值阈值 +- **结果公式**:用于计算实际值的公式 + +```mermaid +classDiagram +class SlaNotificationMessage { ++Long slaId ++String subject ++String message +} +class SlaSenderMessage { ++Long id ++Long workspaceId ++String type ++String name ++String config +} +class SlaConfigMessage { ++Long id ++String type ++String config +} +SlaNotificationMessage --> SlaSenderMessage : "通过" +SlaSenderMessage --> SlaConfigMessage : "包含" +``` + +**图表来源** +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java#L28-L36) +- [SlaSenderMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaSenderMessage.java#L28-L42) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java#L28-L45) + +**本节来源** +- [TaskParameter.java](file://datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/request/TaskParameter.java#L107-L113) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java#L30-L35) + +## 多条件组合告警配置 + +DataVines支持复杂的多条件组合告警配置,允许用户定义基于多个度量指标的复合告警规则。这种配置方式可以实现更精细的监控策略,避免单一指标误报。 + +多条件组合告警的实现机制如下: +1. 系统收集多个度量指标的执行结果 +2. 根据预定义的逻辑关系(AND、OR)进行组合判断 +3. 当组合条件满足时触发告警 + +例如,可以配置"表行数减少超过10% AND 数据新鲜度超过2小时"的复合告警规则,只有当两个条件同时满足时才发送告警。 + +```mermaid +flowchart TD +Start([开始]) --> CollectMetrics["收集多个度量指标结果"] +CollectMetrics --> CheckCondition1["检查条件1: 表行数变化"] +CheckCondition1 --> Condition1Valid{"条件1满足?"} +Condition1Valid --> |是| CheckCondition2["检查条件2: 数据新鲜度"] +Condition1Valid --> |否| NoAlert["不发送告警"] +CheckCondition2 --> Condition2Valid{"条件2满足?"} +Condition2Valid --> |是| SendAlert["发送组合告警"] +Condition2Valid --> |否| NoAlert +SendAlert --> End([结束]) +NoAlert --> End +``` + +**图表来源** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L125-L141) +- [SlaNotificationServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaNotificationServiceImpl.java#L77-L88) + +**本节来源** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L125-L141) +- [SlaNotificationServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaNotificationServiceImpl.java#L77-L88) + +## 告警抑制与升级机制 + +DataVines提供了告警抑制和升级机制,以避免告警风暴并确保重要问题得到及时处理。 + +### 告警抑制 +告警抑制机制用于在特定条件下暂时停止发送重复告警。常见的抑制策略包括: +- **时间窗口抑制**:在指定时间窗口内只发送一次告警 +- **状态变化抑制**:只有当告警状态发生变化时才发送通知 +- **依赖抑制**:当上游任务失败时,抑制下游任务的告警 + +### 告警升级 +告警升级机制确保长时间未解决的问题能够引起更高层级的关注。升级策略包括: +- **时间-based升级**:告警持续一定时间后升级到更高级别的通知渠道 +- **严重性升级**:随着问题持续,逐步增加通知的接收者范围 +- **自动升级**:系统自动将未确认的告警升级到值班经理 + +```mermaid +stateDiagram-v2 +[*] --> Normal +Normal --> Warning : "首次违反SLA" +Warning --> Critical : "持续30分钟未解决" +Critical --> Emergency : "持续2小时未解决" +Warning --> Resolved : "问题解决" +Critical --> Resolved : "问题解决" +Emergency --> Resolved : "问题解决" +Resolved --> Normal : "恢复正常" +state Emergency { +[*] --> NotifyManager +NotifyManager --> NotifyDirector +} +``` + +**图表来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java#L45-L69) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java#L38-L51) + +**本节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java#L45-L69) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java#L38-L51) + +## 通知渠道绑定与优先级设置 + +DataVines支持多种通知渠道的绑定和优先级设置,确保告警信息能够通过最合适的渠道送达相关人员。 + +### 支持的通知渠道 +系统通过插件化架构支持以下通知渠道: +- **邮件通知**:通过SMTP服务器发送电子邮件 +- **钉钉通知**:通过钉钉机器人发送消息 +- **飞书通知**:通过飞书机器人发送消息 +- **企业微信通知**:通过企业微信机器人发送消息 + +### 优先级设置 +通知渠道的优先级通过以下方式配置: +1. **渠道类型优先级**:即时通讯工具通常优先级高于邮件 +2. **接收者角色优先级**:值班人员优先级高于普通开发人员 +3. **时间优先级**:工作时间内的通知优先级高于非工作时间 + +通知渠道的配置通过`SlasHandlerPlugin`接口实现,每个通知插件都必须实现该接口。 + +```mermaid +classDiagram +class SlasHandlerPlugin { ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class EmailSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class DingTalkSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class LarkSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class WecomBotSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +SlasHandlerPlugin <|-- EmailSlasHandlerPlugin +SlasHandlerPlugin <|-- DingTalkSlasHandlerPlugin +SlasHandlerPlugin <|-- LarkSlasHandlerPlugin +SlasHandlerPlugin <|-- WecomBotSlasHandlerPlugin +``` + +**图表来源** +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java#L28-L43) +- [EmailSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java) + +**本节来源** +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java#L28-L43) +- [NotificationConstants.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/constants/NotificationConstants.java#L19-L28) + +## 重复通知间隔与静默期配置 + +为了防止告警信息过度打扰,DataVines提供了重复通知间隔和静默期配置功能。 + +### 重复通知间隔 +重复通知间隔定义了相同告警在未解决情况下重新发送的时间间隔。配置选项包括: +- **固定间隔**:每隔固定时间发送一次提醒 +- **指数退避**:发送间隔随时间指数增长 +- **自定义间隔**:根据告警级别设置不同的间隔 + +### 静默期 +静默期是指在特定时间段内不发送任何告警的配置。常见的静默期设置包括: +- **维护窗口**:系统维护期间自动静默 +- **非工作时间**:夜间或周末自动静默 +- **节假日**:法定节假日自动静默 + +这些配置通过`SlaSenderMessage`和`SlaConfigMessage`中的配置字段实现,具体配置格式由各个通知插件定义。 + +```mermaid +sequenceDiagram +participant JobRunner +participant NotificationManager +participant EmailPlugin +participant DingTalkPlugin +JobRunner->>NotificationManager : notify(message, config) +NotificationManager->>EmailPlugin : notify(message, senderConfig) +alt 告警在静默期内 +EmailPlugin-->>NotificationManager : 返回静默状态 +else 正常告警 +EmailPlugin->>SMTP Server : 发送邮件 +EmailPlugin-->>NotificationManager : 返回发送成功 +end +NotificationManager->>DingTalkPlugin : notify(message, senderConfig) +DingTalkPlugin->>DingTalk API : 发送消息 +DingTalkPlugin-->>NotificationManager : 返回发送结果 +NotificationManager-->>JobRunner : 汇总发送结果 +``` + +**图表来源** +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java#L32-L44) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java#L45-L69) + +**本节来源** +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java#L32-L44) +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L142-L143) + +## SLA告警测试方法 + +DataVines提供了多种SLA告警测试方法,确保告警配置的正确性和可靠性。 + +### 测试接口 +系统提供了专门的测试接口,用于验证告警配置: +- **testSend**:测试特定SLA配置的告警发送功能 +- **test**:测试完整的SLA规则执行流程 + +### 测试步骤 +1. 创建测试用的SLA配置 +2. 调用测试接口发送测试告警 +3. 验证通知渠道是否收到预期消息 +4. 检查告警日志和状态 + +测试功能通过`SlaController`中的测试方法实现,允许用户在配置完成后立即验证告警流程。 + +**本节来源** +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java#Ltest) +- [SlaNotificationServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaNotificationServiceImpl.java#L91-L102) + +## 监控看板集成方案 + +SLA告警系统与DataVines的监控看板深度集成,提供全面的告警可视化功能。 + +### 看板功能 +- **实时告警列表**:显示当前所有活动的告警 +- **历史告警统计**:按时间、类型、级别统计告警历史 +- **SLA合规率**:计算和展示SLA合规情况 +- **告警趋势分析**:分析告警发生的时间趋势 + +### 集成方式 +前端通过`SLAsNoticeList`、`SLAs`和`SLAsSetting`等组件实现告警看板的UI展示,与后端API进行数据交互。 + +```mermaid +graph TB +subgraph "前端UI" +SLAsNoticeList["告警通知列表"] +SLAs["SLA指标"] +SLAsSetting["SLA设置"] +end +subgraph "后端服务" +SlaController["SlaController"] +SlaService["SlaService"] +SlaNotificationService["SlaNotificationService"] +end +SLAsNoticeList --> SlaController: 获取告警列表 +SLAs --> SlaController: 获取SLA指标 +SLAsSetting --> SlaController: 配置SLA规则 +SlaController --> SlaService: 处理业务逻辑 +SlaController --> SlaNotificationService: 处理通知配置 +``` + +**图表来源** +- [index.tsx](file://datavines-ui/src/view/Main/Warning/index.tsx#L8-L21) +- [SlaController.java](file://datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java) + +**本节来源** +- [index.tsx](file://datavines-ui/src/view/Main/Warning/index.tsx#L8-L21) +- [SlaNotificationServiceImpl.java](file://datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaNotificationServiceImpl.java#L77-L88) + +## NotificationManager协调机制 + +`NotificationManager`是SLA告警系统的核心协调组件,负责管理所有通知插件和告警发送流程。 + +### 核心功能 +1. **插件管理**:通过SPI机制加载和管理所有通知插件 +2. **路由分发**:根据配置将告警消息分发到相应的通知插件 +3. **结果聚合**:汇总各个通知渠道的发送结果 +4. **异常处理**:处理通知发送过程中的异常情况 + +### 工作流程 +```mermaid +sequenceDiagram +participant Client as "客户端" +participant NotificationClient as "NotificationClient" +participant NotificationManager as "NotificationManager" +participant Plugin as "通知插件" +Client->>NotificationClient : 发送告警请求 +NotificationClient->>NotificationManager : 转发请求 +NotificationManager->>NotificationManager : 验证配置 +loop 每个通知配置 +NotificationManager->>Plugin : 调用notify方法 +Plugin->>外部系统 : 发送通知 +Plugin-->>NotificationManager : 返回发送结果 +NotificationManager->>NotificationManager : 合并结果 +end +NotificationManager-->>NotificationClient : 返回汇总结果 +NotificationClient-->>Client : 返回最终结果 +``` + +**图表来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java#L45-L69) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java#L32-L44) + +**本节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java#L33-L71) +- [NotificationClientImpl.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java#L32-L44) + +## 配置示例与最佳实践 + +### 配置示例 +```json +{ + "slaId": 1001, + "threshold": 0.1, + "operator": "GREATER_THAN", + "notificationConfig": [ + { + "sender": { + "type": "email", + "config": "{\"smtpHost\":\"smtp.example.com\",\"port\":587}" + }, + "receivers": [ + { + "type": "email", + "config": "{\"to\":\"dev-team@example.com\"}" + } + ] + }, + { + "sender": { + "type": "dingtalk", + "config": "{\"webhook\":\"https://oapi.dingtalk.com/robot/send?access_token=xxx\"}" + }, + "receivers": [ + { + "type": "dingtalk", + "config": "{\"atMobiles\":[\"13800138000\"]}" + } + ] + } + ] +} +``` + +### 最佳实践 +1. **分层告警**:根据问题严重性配置不同级别的通知 +2. **合理设置静默期**:避免在维护期间收到不必要的告警 +3. **定期测试配置**:确保所有通知渠道正常工作 +4. **监控告警系统自身**:确保告警系统本身的可靠性 +5. **文档化SLA规则**:便于团队成员理解和维护 + +**本节来源** +- [JobRunner.java](file://datavines-runner/src/main/java/io/datavines/runner/JobRunner.java#L125-L141) +- [SlaConfigVO.java](file://datavines-server/src/main/java/io/datavines/server/api/dto/vo/SlaConfigVO.java#L26-L33) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java#L30-L35) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\344\274\201\344\270\232\345\276\256\344\277\241\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\344\274\201\344\270\232\345\276\256\344\277\241\351\205\215\347\275\256.md" new file mode 100644 index 00000000..12e5f7d2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\344\274\201\344\270\232\345\276\256\344\277\241\351\205\215\347\275\256.md" @@ -0,0 +1,264 @@ +# 企业微信配置 + + +**本文档引用的文件** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java) +- [WecomBotSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSender.java) +- [ReceiverConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/entity/ReceiverConfig.java) +- [WecomBotConstants.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotConstants.java) +- [ContentUtil.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/utils/ContentUtil.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java) +- [useNotificationFormModal.tsx](file://datavines-ui/src/view/Main/Warning/SLAsSetting/useNotificationFormModal.tsx) + + +## 目录 +1. [简介](#简介) +2. [企业微信机器人Webhook URL获取与配置](#企业微信机器人webhook-url获取与配置) +3. [消息类型支持](#消息类型支持) +4. [消息模板自定义](#消息模板自定义) +5. [部门/成员通知策略](#部门成员通知策略) +6. [测试方法](#测试方法) +7. [常见错误处理方案](#常见错误处理方案) +8. [WecomBotSlasHandlerPlugin实现机制](#wecombotslashandlerplugin实现机制) +9. [通过企业微信API实现更复杂的通知场景](#通过企业微信api实现更复杂的通知场景) + +## 简介 +DataVines是一个易于使用的数据质量服务平台,支持多种指标。该平台基于插件设计,其中通知渠道支持企业微信。本文档详细说明如何在DataVines中配置企业微信通知渠道,包括企业微信机器人Webhook URL的获取与配置、消息类型支持(文本、图文、Markdown)、消息模板的自定义、部门/成员通知策略。同时提供企业微信通知的测试方法和常见错误处理方案,并解释WecomBotSlasHandlerPlugin的实现机制,以及如何通过企业微信API实现更复杂的通知场景。 + +## 企业微信机器人Webhook URL获取与配置 +在DataVines中配置企业微信通知渠道的第一步是获取企业微信机器人的Webhook URL。用户需要在企业微信中创建一个群聊机器人,并获取其Webhook地址。此Webhook地址将用于发送通知消息。 + +在DataVines系统中,企业微信通知的配置主要通过`WecomBotSlasHandlerPlugin`类来完成。该类实现了`SlasHandlerPlugin`接口,负责处理SLA(Service Level Agreement)相关的通知逻辑。在配置过程中,用户需要提供Webhook URL作为必填项,该配置项通过`InputParam`对象定义,并设置了`required=true`验证规则。 + +```mermaid +flowchart TD +Start([开始]) --> CreateRobot["在企业微信中创建群聊机器人"] +CreateRobot --> GetWebhook["获取机器人的Webhook URL"] +GetWebhook --> ConfigureDataVines["在DataVines中配置Webhook URL"] +ConfigureDataVines --> ValidateConfig["验证配置有效性"] +ValidateConfig --> End([结束]) +``` + +**图示来源** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java#L83-L85) + +## 消息类型支持 +DataVines的企业微信通知插件支持多种消息类型,主要包括文本、图文和Markdown格式。根据企业微信API的规范,当前实现主要使用Markdown消息类型进行通知。 + +在`WecomBotConstants`类中定义了消息类型相关的常量,其中`MARKDOWN`常量值为"markdown",表示使用Markdown格式的消息。当发送通知时,系统会构建符合企业微信API要求的JSON格式消息体,其中包含`msgtype`字段,其值设置为`markdown`。 + +```mermaid +classDiagram +class WecomBotConstants { ++static final String MSG_TYPE = "msgtype" ++static final String MARKDOWN = "markdown" ++static final String CONTENT = "content" ++static final String FIRST_TITLE_START = "# " ++static final String QUOTE_START = "> " ++static final String END = "\n" +} +``` + +**图示来源** +- [WecomBotConstants.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotConstants.java#L19-L26) + +## 消息模板自定义 +DataVines允许用户自定义企业微信通知的消息模板。消息模板的构建由`WecomBotSender`类的`getMarkdownMessage`方法完成。该方法接收主题(subject)和内容(content)两个参数,然后按照预定义的格式生成Markdown消息。 + +消息模板的结构如下: +- 主题部分以一级标题形式显示,前面加上`# `符号 +- 内容部分每行前面加上`> `符号,表示引用格式 +- 支持对特定类型的消息(如"任务执行记录")进行特殊格式化处理,将其转换为可点击的链接 + +```mermaid +flowchart TD +Start([开始]) --> CheckSubject["检查主题是否为空"] +CheckSubject --> |是| AddSubject["添加主题到消息内容"] +CheckSubject --> |否| CheckContent["检查内容是否为空"] +AddSubject --> CheckContent +CheckContent --> |是| ParseContent["解析内容为JSON数组"] +CheckContent --> |否| ReturnEmpty["返回空消息"] +ParseContent --> LoopStart["遍历数组元素"] +LoopStart --> CheckTaskRecord["检查是否为任务执行记录"] +CheckTaskRecord --> |是| FormatAsLink["格式化为链接"] +CheckTaskRecord --> |否| FormatAsQuote["格式化为引用"] +FormatAsLink --> AddToContent["添加到消息内容"] +FormatAsQuote --> AddToContent +AddToContent --> CheckLast["是否为最后一个元素"] +CheckLast --> |否| LoopStart +CheckLast --> |是| ReturnResult["返回最终消息"] +``` + +**图示来源** +- [WecomBotSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSender.java#L76-L94) + +## 部门/成员通知策略 +在DataVines中,企业微信通知的接收者通过`ReceiverConfig`类进行配置。该类包含一个`webhook`字段,用于存储企业微信机器人的Webhook URL。通过不同的Webhook URL,可以实现向不同部门或成员发送通知的策略。 + +通知策略的实现机制如下: +1. 在SLA配置中,用户可以选择通知类型为"wecombot" +2. 系统会收集所有类型为"wecombot"的发送者配置 +3. 对于每个发送者,系统会解析其配置信息,创建`ReceiverConfig`对象 +4. 将所有接收者配置添加到集合中,统一发送通知 + +```mermaid +sequenceDiagram +participant UI as "用户界面" +participant Backend as "后端服务" +participant WecomBot as "WecomBotSlasHandlerPlugin" +participant Sender as "WecomBotSender" +UI->>Backend : 提交SLA通知配置 +Backend->>WecomBot : 调用notify方法 +WecomBot->>WecomBot : 过滤wecombot类型的发送者 +WecomBot->>WecomBot : 解析接收者配置 +WecomBot->>Sender : 创建WecomBotSender实例 +Sender->>Sender : 构建Markdown消息 +Sender->>Sender : 发送HTTP POST请求 +Sender-->>WecomBot : 返回发送结果 +WecomBot-->>Backend : 返回通知结果 +Backend-->>UI : 显示配置结果 +``` + +**图示来源** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java#L36-L52) +- [WecomBotSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSender.java#L40-L73) + +## 测试方法 +为了确保企业微信通知配置的正确性,DataVines提供了相应的测试方法。测试过程主要包括以下步骤: + +1. 在UI界面配置企业微信通知,填写正确的Webhook URL +2. 保存配置后,系统会调用`WecomBotSlasHandlerPlugin`的`notify`方法 +3. 该方法会创建`WecomBotSender`实例,并调用其`sendMsg`方法发送测试消息 +4. 如果发送成功,企业微信群聊中会收到格式化的通知消息;如果失败,系统会记录错误信息 + +测试时需要注意: +- 确保Webhook URL正确无误 +- 检查网络连接是否正常 +- 验证企业微信机器人是否已正确添加到目标群聊 + +```mermaid +flowchart TD +Start([开始测试]) --> ConfigureWebhook["配置Webhook URL"] +ConfigureWebhook --> SaveConfig["保存配置"] +SaveConfig --> TriggerTest["触发测试通知"] +TriggerTest --> SendRequest["发送HTTP POST请求"] +SendRequest --> CheckResponse["检查响应结果"] +CheckResponse --> |成功| ReceiveMessage["企业微信收到消息"] +CheckResponse --> |失败| LogError["记录错误日志"] +ReceiveMessage --> TestSuccess["测试成功"] +LogError --> TestFailed["测试失败"] +TestSuccess --> End([结束]) +TestFailed --> End +``` + +**图示来源** +- [WecomBotSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSender.java#L54-L58) + +## 常见错误处理方案 +在配置和使用企业微信通知时,可能会遇到一些常见问题。以下是这些问题及其解决方案: + +1. **Webhook URL错误** + - 现象:发送通知失败,日志中显示"send to [webhook] fail" + - 解决方案:检查Webhook URL是否正确,确保没有多余的空格或字符 + +2. **网络连接问题** + - 现象:发送超时或连接被拒绝 + - 解决方案:检查服务器网络连接,确保可以访问企业微信API服务器 + +3. **消息格式错误** + - 现象:企业微信返回错误码非0 + - 解决方案:检查消息内容是否符合Markdown语法,避免使用不支持的格式 + +4. **权限问题** + - 现象:返回403错误 + - 解决方案:确认企业微信机器人是否有发送消息的权限 + +错误处理主要在`WecomBotSender`类的`sendMsg`方法中实现。该方法使用try-catch块捕获异常,并将失败的Webhook URL记录到`failToReceivers`集合中。如果存在发送失败的情况,最终结果的状态会被设置为false,并包含失败原因。 + +```mermaid +flowchart TD +Start([开始]) --> TrySend["尝试发送消息"] +TrySend --> |成功| CheckResponse["检查响应结果"] +TrySend --> |异常| CatchException["捕获异常"] +CatchException --> AddToFail["添加到失败列表"] +CheckResponse --> |失败| AddToFail +CheckResponse --> |成功| CheckAllSuccess["检查是否全部成功"] +AddToFail --> CheckAllSuccess +CheckAllSuccess --> |有失败| SetStatusFalse["设置状态为失败"] +CheckAllSuccess --> |无失败| SetStatusTrue["设置状态为成功"] +SetStatusFalse --> ReturnResult["返回结果"] +SetStatusTrue --> ReturnResult +``` + +**图示来源** +- [WecomBotSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSender.java#L49-L72) + +## WecomBotSlasHandlerPlugin实现机制 +`WecomBotSlasHandlerPlugin`是DataVines中企业微信通知的核心实现类。它实现了`SlasHandlerPlugin`接口,负责处理SLA相关的通知逻辑。 + +该类的主要功能包括: +1. `notify`方法:处理通知请求,收集所有企业微信类型的发送者,逐个发送通知 +2. `getConfigJson`方法:返回配置项的JSON字符串,定义了Webhook URL为必填项 +3. `getConfigSenderJson`方法:返回发送者配置的JSON字符串 + +`notify`方法的执行流程如下: +1. 从配置中筛选出类型为"wecombot"的发送者 +2. 为每个发送者创建`WecomBotSender`实例 +3. 解析接收者配置,创建`ReceiverConfig`对象 +4. 调用`WecomBotSender`的`sendMsg`方法发送消息 +5. 收集所有发送结果,合并成最终结果返回 + +```mermaid +classDiagram +class WecomBotSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class SlasHandlerPlugin { ++notify(SlaNotificationMessage, Map) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class WecomBotSender { ++sendMsg(Set, String, String) SlaNotificationResultRecord +} +class ReceiverConfig { ++webhook String +} +WecomBotSlasHandlerPlugin --> SlasHandlerPlugin : "实现" +WecomBotSlasHandlerPlugin --> WecomBotSender : "使用" +WecomBotSlasHandlerPlugin --> ReceiverConfig : "使用" +``` + +**图示来源** +- [WecomBotSlasHandlerPlugin.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java#L34-L62) + +## 通过企业微信API实现更复杂的通知场景 +虽然当前DataVines的企业微信通知插件主要支持基本的Markdown消息,但可以通过扩展`WecomBotSender`类来实现更复杂的通知场景。企业微信API支持多种消息类型,包括文本、图片、图文、文件、音频、视频等。 + +可能的扩展方向包括: +1. **图文消息支持**:通过添加`news`类型的消息支持,可以发送包含标题、描述、图片和链接的富媒体消息 +2. **模板卡片支持**:使用模板卡片可以创建交互式的消息,支持按钮点击等操作 +3. **消息卡片支持**:通过消息卡片可以展示更丰富的信息结构 + +要实现这些功能,需要: +1. 扩展`WecomBotConstants`类,添加新的消息类型常量 +2. 修改`ContentUtil`类的`createParamMap`方法,支持构建更复杂的消息结构 +3. 在`WecomBotSender`类中添加新的方法,用于构建和发送不同类型的消息 +4. 更新`WecomBotSlasHandlerPlugin`的配置项,允许用户选择不同的消息类型 + +```mermaid +flowchart TD +Start([开始扩展]) --> DefineConstants["定义新的消息类型常量"] +DefineConstants --> ExtendContentUtil["扩展ContentUtil类"] +ExtendContentUtil --> AddNewMethods["在WecomBotSender中添加新方法"] +AddNewMethods --> UpdateConfig["更新WecomBotSlasHandlerPlugin配置"] +UpdateConfig --> TestImplementation["测试新功能"] +TestImplementation --> DocumentChanges["更新文档"] +DocumentChanges --> End([结束]) +``` + +**图示来源** +- [ContentUtil.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/utils/ContentUtil.java#L23-L37) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\200\232\347\237\245\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\200\232\347\237\245\351\205\215\347\275\256.md" new file mode 100644 index 00000000..8a9342c6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\200\232\347\237\245\351\205\215\347\275\256.md" @@ -0,0 +1,244 @@ +# 通知配置 + + +**本文档引用文件** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) +- [NotificationConstants.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/constants/NotificationConstants.java) +- [DingTalkSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSender.java) +- [EMailSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java) +- [LarkSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSender.java) +- [WecomBotSender.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSender.java) +- [ReceiverConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/entity/ReceiverConfig.java) +- [NotificationConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/entity/NotificationConfig.java) + + +## 目录 +1. [简介](#简介) +2. [通知渠道配置](#通知渠道配置) +3. [SLA告警规则与通知策略](#sla告警规则与通知策略) +4. [通知系统可靠性保障](#通知系统可靠性保障) +5. [自定义通知渠道集成](#自定义通知渠道集成) +6. [通过API发送通知](#通过api发送通知) + +## 简介 +DataVines 提供了灵活的通知系统,支持多种通知渠道,包括钉钉、邮件、飞书和企业微信。该系统允许用户配置SLA(服务等级协议)告警规则,并根据预设策略自动发送通知。本文档详细说明如何配置这些功能,确保数据质量监控的及时性和有效性。 + +## 通知渠道配置 + +### 钉钉通知配置 +钉钉通知通过Webhook和密钥进行身份验证。用户需在钉钉群中添加自定义机器人,获取Webhook地址和安全密钥。配置项包括: +- **Webhook**: 机器人回调地址 +- **Secret**: 安全密钥,用于生成签名 +- **At Mobiles**: 需要@的手机号列表 +- **At Dingtalk IDs**: 需要@的Dingtalk ID列表 +- **Is At All**: 是否@所有人 + +配置信息以JSON格式存储,由`ReceiverConfig`类解析并用于构建请求。 + +### 邮件通知配置 +邮件通知支持SMTP协议,需配置以下参数: +- **Server Host**: SMTP服务器地址 +- **Server Port**: SMTP端口 +- **Sender**: 发件人邮箱 +- **User**: 登录用户名 +- **Passwd**: 登录密码 +- **Enable Smtp Auth**: 是否启用SMTP认证 +- **Starttls Enable**: 是否启用STARTTLS +- **Ssl Enable**: 是否启用SSL +- **Smtp Ssl Trust**: SSL信任主机 + +邮件发送使用`HtmlEmail`组件,支持HTML格式内容,并通过`EMailSender`类封装发送逻辑。 + +### 飞书通知配置 +飞书通知通过群组机器人Webhook实现。主要配置包括: +- **Webhook**: 机器人Webhook地址 +- **Group Name**: 群组名称(用于日志记录) +- **At All**: 是否@所有人 + +消息以卡片形式发送,标题、颜色和内容可自定义,由`LarkSender`类处理发送流程。 + +### 企业微信通知配置 +企业微信通知通过群机器人Webhook实现。配置项包括: +- **Webhook**: 机器人Webhook地址 + +消息以Markdown格式发送,支持链接和引用格式,由`WecomBotSender`类负责构建和发送消息。 + +**通知渠道通用配置结构** +```json +{ + "receiverType": "dingtalk|email|lark|wecombot", + "config": { + // 渠道特定配置 + } +} +``` + +**节来源** +- [ReceiverConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/entity/ReceiverConfig.java) +- [NotificationConfig.java](file://datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/entity/NotificationConfig.java) + +## SLA告警规则与通知策略 + +### SLA告警规则配置 +SLA告警规则定义了数据质量检查的阈值和触发条件。当数据质量指标违反SLA时,系统将生成告警消息。`SlaNotificationMessage`类包含以下字段: +- **slaId**: SLA规则ID +- **subject**: 告警主题 +- **message**: 告警内容 + +告警内容通常包含任务执行记录、数据异常详情等信息。 + +### 通知策略 +通知策略决定了告警消息的发送方式和接收人。系统支持多渠道、多接收人配置。`SlaConfigMessage`类定义了接收人配置: +- **id**: 配置ID +- **type**: 接收人类型(如email、dingtalk) +- **config**: 接收人具体配置(JSON字符串) + +通知策略通过`NotificationManager`统一管理,根据配置调用相应的`SlasHandlerPlugin`实现发送。 + +```mermaid +classDiagram +class SlaNotificationMessage { ++Long slaId ++String subject ++String message +} +class SlaConfigMessage { ++Long id ++String type ++String config +} +class SlaSenderMessage { ++String type ++String config +} +class SlaNotificationResult { ++boolean status ++String message +} +class NotificationManager { ++Set supportedPlugins ++SlaNotificationResult notify(SlaNotificationMessage, Map>) +} +class SlasHandlerPlugin { +<> ++SlaNotificationResult notify(SlaNotificationMessage, Map>) ++String getConfigSenderJson() ++String getConfigJson() +} +NotificationManager --> SlasHandlerPlugin : "使用" +SlaNotificationMessage --> SlaNotificationResult : "返回" +SlaSenderMessage --> SlaConfigMessage : "包含" +``` + +**图来源** +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) + +**节来源** +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) +- [SlaConfigMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaConfigMessage.java) + +## 通知系统可靠性保障 + +### 重试机制 +当前通知系统在单次发送失败时会记录失败接收人,但未实现自动重试机制。建议在生产环境中结合外部监控系统实现重试逻辑。 + +### 失败告警 +系统通过`SlaNotificationResult`记录发送结果: +- **status**: 发送状态(true/false) +- **message**: 失败详情(包含失败的接收人列表) + +发送失败时,日志中会记录详细错误信息,便于排查问题。 + +### 可靠性增强建议 +1. **引入消息队列**:将通知消息写入Kafka或RabbitMQ,实现异步发送和持久化。 +2. **实现重试策略**:对失败通知进行指数退避重试。 +3. **添加监控告警**:对通知发送失败率进行监控,超过阈值时触发二次告警。 + +**节来源** +- [SlaNotificationResult.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationResult.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +## 自定义通知渠道集成 + +### 扩展机制 +DataVines采用SPI(Service Provider Interface)机制支持自定义通知渠道。开发者需实现`SlasHandlerPlugin`接口,并在`META-INF/plugins`目录下注册实现类。 + +### 实现步骤 +1. 创建新模块,依赖`datavines-notification-api` +2. 实现`SlasHandlerPlugin`接口 +3. 重写`notify`方法,实现具体发送逻辑 +4. 提供`getConfigSenderJson`和`getConfigJson`方法,返回配置项JSON +5. 在`META-INF/plugins/io.datavines.notification.api.spi.SlasHandlerPlugin`文件中添加实现类全名 + +### 示例:自定义短信通知 +```java +@SPI +public class SmsSlasHandlerPlugin implements SlasHandlerPlugin { + @Override + public SlaNotificationResult notify(SlaNotificationMessage message, Map> config) { + // 实现短信发送逻辑 + return new SlaNotificationResult(true, "发送成功"); + } + + @Override + public String getConfigSenderJson() { + return "{\"serverUrl\":\"短信网关地址\",\"apiKey\":\"API密钥\"}"; + } + + @Override + public String getConfigJson() { + return "{\"phoneNumbers\":\"接收手机号\",\"templateId\":\"模板ID\"}"; + } +} +``` + +**节来源** +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) + +## 通过API发送通知 + +### API调用流程 +1. 构造`SlaNotificationMessage`对象,设置主题和内容 +2. 构造`SlaSenderMessage`对象,设置渠道类型和配置 +3. 构造`SlaConfigMessage`对象,设置接收人配置 +4. 调用`NotificationManager.notify()`方法发送通知 + +### 代码示例 +```java +// 创建通知消息 +SlaNotificationMessage message = new SlaNotificationMessage(); +message.setSubject("数据质量告警"); +message.setMessage("[\"任务执行失败: http://localhost:8888/job/123\"]"); + +// 创建发送者配置 +SlaSenderMessage sender = new SlaSenderMessage(); +sender.setType("email"); +sender.setConfig("{\"serverHost\":\"smtp.example.com\",\"serverPort\":\"587\",\"sender\":\"alert@example.com\",\"user\":\"alert\",\"passwd\":\"password\",\"enableSmtpAuth\":\"true\",\"starttlsEnable\":\"true\",\"sslEnable\":\"false\",\"smtpSslTrust\":\"*\"}"); + +// 创建接收人配置 +SlaConfigMessage config = new SlaConfigMessage(); +config.setType("email"); +config.setConfig("[\"user1@example.com\",\"user2@example.com\"]"); + +// 调用通知管理器 +Map> configMap = new HashMap<>(); +configMap.put(sender, Collections.singleton(config)); +SlaNotificationResult result = notificationManager.notify(message, configMap); +``` + +### 错误处理 +- **渠道不支持**:抛出`DataVinesException`,提示"sender type not support" +- **配置缺失**:抛出`DataVinesException`,提示"message cannot be send without sender and receiver" +- **发送失败**:返回`SlaNotificationResult`,status为false,包含失败详情 + +**节来源** +- [NotificationManager.java](file://datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java) +- [SlasHandlerPlugin.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java) +- [SlaNotificationMessage.java](file://datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/entity/SlaNotificationMessage.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\202\256\344\273\266\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\202\256\344\273\266\351\205\215\347\275\256.md" new file mode 100644 index 00000000..7b96194f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\202\256\344\273\266\351\205\215\347\275\256.md" @@ -0,0 +1,368 @@ +# 邮件配置 + + +**本文档引用的文件** +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\entity\ReceiverConfig.java) +- [SlaSenderMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaSenderMessage.java) +- [SlaConfigMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaConfigMessage.java) +- [application.yaml](file://datavines-server\src\main\resources\application.yaml) +- [EmailConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailConstants.java) +- [NotificationConstants.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\constants\NotificationConstants.java) + + +## 目录 +1. [简介](#简介) +2. [SMTP服务器设置](#smtp服务器设置) +3. [发件人账户认证](#发件人账户认证) +4. [SSL/TLS加密配置](#ssltls加密配置) +5. [邮件模板定制](#邮件模板定制) +6. [收件人列表管理](#收件人列表管理) +7. [邮件通知测试方法](#邮件通知测试方法) +8. [常见问题解决方案](#常见问题解决方案) +9. [EmailSlasHandlerPlugin实现原理](#emailslashandlerplugin实现原理) +10. [通过配置文件或API管理邮件通知策略](#通过配置文件或api方式管理邮件通知策略) + +## 简介 +DataVines提供了一套完整的邮件通知系统,用于在数据质量检查、任务执行等场景下向相关人员发送通知。本文档详细说明了如何在DataVines中配置邮件通知渠道,包括SMTP服务器设置、发件人账户认证、SSL/TLS加密配置、邮件模板定制、收件人列表管理等方面的内容。同时,本文档还提供了邮件通知的测试方法和常见问题解决方案,并解释了EmailSlasHandlerPlugin的实现原理以及如何通过配置文件或API方式管理邮件通知策略。 + +## SMTP服务器设置 +在DataVines中配置邮件通知时,首先需要设置SMTP服务器的相关参数。这些参数包括SMTP服务器地址、端口号、发件人邮箱等。根据代码分析,SMTP服务器的配置主要通过`EmailSlasHandlerPlugin`类中的`getConfigSenderJson`方法定义。 + +**SMTP服务器配置参数:** +- **serverHost**: SMTP服务器地址,为必填项 +- **serverPort**: SMTP服务器端口号,默认值为25 +- **sender**: 发件人邮箱地址,为必填项 + +这些配置参数在`EmailSlasHandlerPlugin`类中通过`InputParam`对象进行定义,并在创建邮件发送器时从配置中读取。例如,在`EMailSender`类的构造函数中,会从`SlaSenderMessage`对象的配置字符串中解析出这些参数: + +```mermaid +flowchart TD +A[开始] --> B[获取SlaSenderMessage配置] +B --> C[解析JSON配置字符串] +C --> D[提取serverHost] +D --> E[提取serverPort] +E --> F[提取sender] +F --> G[验证必填参数] +G --> H[初始化邮件发送器] +H --> I[结束] +``` + +**代码路径** +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L101-L110) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L73-L80) + +## 发件人账户认证 +DataVines支持通过用户名和密码的方式对SMTP服务器进行身份验证。在配置邮件通知时,可以启用SMTP认证功能,并提供相应的用户名和密码。 + +**发件人账户认证配置:** +- **enableSmtpAuth**: 是否启用SMTP认证,可选值为"YES"/"TRUE"或"NO"/"FALSE",默认值为"TRUE" +- **user**: SMTP认证用户名,当启用认证时为必填项 +- **passwd**: SMTP认证密码,当启用认证时为必填项 + +在`EmailSlasHandlerPlugin`类中,这些参数通过`RadioParam`和`InputParam`对象进行定义。当创建`EMailSender`实例时,会从配置中读取这些参数,并在创建邮件会话时使用它们进行身份验证。 + +```mermaid +sequenceDiagram +participant 配置界面 +participant EmailSlasHandlerPlugin +participant EMailSender +participant SMTP服务器 +配置界面->>EmailSlasHandlerPlugin : 提交SMTP认证配置 +EmailSlasHandlerPlugin->>EMailSender : 创建邮件发送器实例 +EMailSender->>EMailSender : 从配置中读取认证参数 +EMailSender->>SMTP服务器 : 使用用户名和密码进行身份验证 +SMTP服务器-->>EMailSender : 认证成功/失败 +EMailSender-->>EmailSlasHandlerPlugin : 返回认证结果 +EmailSlasHandlerPlugin-->>配置界面 : 显示配置结果 +``` + +**代码路径** +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L116-L129) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L82-L88) + +## SSL/TLS加密配置 +为了确保邮件传输的安全性,DataVines支持SSL和TLS加密协议。用户可以根据SMTP服务器的要求配置相应的加密选项。 + +**SSL/TLS加密配置参数:** +- **starttlsEnable**: 是否启用STARTTLS加密,可选值为"YES"/"TRUE"或"NO"/"FALSE",默认值为"FALSE" +- **sslEnable**: 是否启用SSL加密,可选值为"YES"/"TRUE"或"NO"/"FALSE",默认值为"FALSE" +- **smtpSslTrust**: 是否信任SSL证书,可选值为"YES"/"TRUE"或"NO"/"FALSE",默认值为"FALSE" + +这些加密配置在`EmailSlasHandlerPlugin`类中通过`RadioParam`对象进行定义,并在`EMailSender`类的`getSession`方法中应用到邮件会话的属性中。特别地,当`smtpSslTrust`设置为"TRUE"时,系统会将SMTP服务器地址添加到信任的SSL主机列表中。 + +```mermaid +flowchart TD +A[开始] --> B[读取SSL/TLS配置] +B --> C{starttlsEnable为TRUE?} +C --> |是| D[设置mail.smtp.starttls.enable为true] +C --> |否| E[不设置STARTTLS] +D --> F +E --> F +F --> G{sslEnable为TRUE?} +G --> |是| H[设置mail.smtp.ssl.enable为true] +G --> |否| I[不设置SSL] +H --> J +I --> J +J --> K{smtpSslTrust为TRUE?} +K --> |是| L[设置mail.smtp.ssl.trust为serverHost] +K --> |否| M[不设置SSL信任] +L --> N +M --> N +N --> O[创建安全邮件会话] +O --> P[结束] +``` + +**代码路径** +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L131-L150) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L90-L97) + +## 邮件模板定制 +DataVines允许用户自定义邮件内容模板,以满足不同场景下的通知需求。邮件模板支持HTML格式,并包含预定义的样式和布局。 + +**邮件模板特性:** +- 使用HTML 4.01 Transitional DOCTYPE +- 包含标题、样式表和元信息 +- 表格布局,边框为1px,单元格间距为5px +- 字体大小为15px +- 支持链接格式化,特别是任务执行记录的链接 + +在`EmailConstants`类中定义了邮件模板的各个组成部分,包括HTML头部、表格尾部、正文尾部等。`EMailSender`类的`getTextTypeMessage`方法负责将原始消息内容转换为格式化的HTML邮件内容。 + +```mermaid +classDiagram +class EmailConstants { ++static final String HTML_HEADER_PREFIX ++static final String TABLE_HTML_TAIL ++static final String BODY_HTML_TAIL ++static final String TR ++static final String TD ++static final String TD_END ++static final String TR_END +} +class EMailSender { +-String getTextTypeMessage(String content) ++SlaNotificationResultRecord sendMails(Set, Set, String, String) +} +EmailConstants --> EMailSender : "使用常量" +``` + +**代码路径** +- [EmailConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailConstants.java#L56-L70) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L178-L196) + +## 收件人列表管理 +DataVines支持灵活的收件人管理机制,允许用户配置主要收件人(To)和抄送收件人(Cc)。收件人列表可以通过逗号或分号分隔多个邮箱地址。 + +**收件人配置参数:** +- **to**: 主要收件人邮箱列表,为必填项,支持多个邮箱地址,用逗号或分号分隔 +- **cc**: 抄送收件人邮箱列表,为可选项,支持多个邮箱地址,用逗号或分号分隔 + +在`ReceiverConfig`类中定义了收件人配置的数据结构,包含`to`和`cc`两个字段。`EmailSlasHandlerPlugin`类的`notify`方法负责解析这些配置,并将收件人地址添加到邮件中。 + +```mermaid +flowchart TD +A[开始] --> B[获取收件人配置] +B --> C[解析to字段] +C --> D[按逗号或分号分割] +D --> E[去重并添加到收件人集合] +E --> F[检查cc字段] +F --> G{cc字段存在?} +G --> |是| H[按逗号或分号分割] +H --> I[去重并添加到抄送集合] +G --> |否| J[跳过抄送] +I --> K[发送邮件] +J --> K +K --> L[结束] +``` + +**代码路径** +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\entity\ReceiverConfig.java#L30-L33) +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L63-L70) + +## 邮件通知测试方法 +DataVines提供了多种测试邮件通知配置的方法,确保配置正确无误后才能投入使用。 + +**测试方法:** +1. **配置验证测试**:在保存配置时,系统会验证所有必填字段是否已填写,如SMTP服务器地址、端口、发件人邮箱等。 +2. **连接测试**:尝试与SMTP服务器建立连接,验证服务器地址和端口是否正确。 +3. **认证测试**:如果启用了SMTP认证,系统会使用提供的用户名和密码进行登录测试。 +4. **发送测试**:向指定的测试邮箱发送一封测试邮件,验证整个邮件发送流程是否正常。 + +测试过程中,系统会记录详细的日志信息,包括连接状态、认证结果和发送状态。如果测试失败,系统会返回具体的错误信息,帮助用户排查问题。 + +```mermaid +sequenceDiagram +participant 用户 +participant UI界面 +participant EmailSlasHandlerPlugin +participant EMailSender +participant SMTP服务器 +用户->>UI界面 : 输入邮件配置并点击测试 +UI界面->>EmailSlasHandlerPlugin : 调用测试接口 +EmailSlasHandlerPlugin->>EMailSender : 创建邮件发送器 +EMailSender->>EMailSender : 验证配置参数 +EMailSender->>SMTP服务器 : 建立连接 +SMTP服务器-->>EMailSender : 连接成功 +EMailSender->>SMTP服务器 : 发送认证信息 +SMTP服务器-->>EMailSender : 认证成功 +EMailSender->>SMTP服务器 : 发送测试邮件 +SMTP服务器-->>EMailSender : 发送成功 +EMailSender-->>EmailSlasHandlerPlugin : 返回成功结果 +EmailSlasHandlerPlugin-->>UI界面 : 显示测试成功 +UI界面-->>用户 : 显示测试结果 +``` + +**代码路径** +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L100-L141) +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L46-L93) + +## 常见问题解决方案 +在配置和使用邮件通知功能时,可能会遇到一些常见问题。以下是这些问题的解决方案: + +**1. 连接超时问题** +- **问题描述**:无法连接到SMTP服务器,出现连接超时错误。 +- **解决方案**: + - 检查SMTP服务器地址和端口是否正确 + - 确认网络连接是否正常,防火墙是否阻止了相应端口 + - 尝试使用telnet命令测试SMTP服务器端口是否开放 + +**2. 认证失败问题** +- **问题描述**:SMTP认证失败,返回用户名或密码错误。 +- **解决方案**: + - 确认用户名和密码是否正确 + - 检查是否需要使用应用专用密码而非账户密码 + - 确认SMTP服务器是否要求特定的认证方式 + +**3. SSL/TLS握手失败** +- **问题描述**:SSL/TLS握手失败,出现证书验证错误。 +- **解决方案**: + - 检查SSL/TLS配置是否与SMTP服务器要求匹配 + - 尝试启用或禁用`smtpSslTrust`选项 + - 确认服务器证书是否有效且受信任 + +**4. 邮件发送失败** +- **问题描述**:邮件发送失败,但没有具体错误信息。 +- **解决方案**: + - 启用邮件发送的调试模式,查看详细日志 + - 检查收件人邮箱地址格式是否正确 + - 确认发件人邮箱是否有发送限制 + +**代码路径** +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L137-L140) +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L74-L88) + +## EmailSlasHandlerPlugin实现原理 +`EmailSlasHandlerPlugin`是DataVines邮件通知功能的核心实现类,它实现了`SlasHandlerPlugin`接口,负责处理邮件通知的整个流程。 + +**核心组件关系:** +- `EmailSlasHandlerPlugin`:主控制器,负责协调整个邮件通知流程 +- `EMailSender`:邮件发送器,负责实际的邮件发送操作 +- `ReceiverConfig`:收件人配置,定义收件人信息的数据结构 +- `SlaSenderMessage`:发件人消息,包含SMTP服务器配置信息 +- `SlaConfigMessage`:通知配置消息,包含收件人配置信息 + +**工作流程:** +1. 接收`SlaNotificationMessage`对象,包含通知主题和内容 +2. 从配置映射中筛选出类型为"email"的发送器配置 +3. 为每个邮件发送器创建`EMailSender`实例 +4. 解析收件人配置,提取主要收件人和抄送收件人 +5. 调用`EMailSender`的`sendMails`方法发送邮件 +6. 收集发送结果,合并成最终的通知结果 + +```mermaid +classDiagram +class SlasHandlerPlugin { +<> ++notify(SlaNotificationMessage, Map>) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class EmailSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map>) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class EMailSender { ++EMailSender(SlaSenderMessage) ++sendMails(Set, Set, String, String) SlaNotificationResultRecord +} +class SlaSenderMessage { ++String type ++String config +} +class SlaConfigMessage { ++String type ++String config +} +class ReceiverConfig { ++String to ++String cc +} +SlasHandlerPlugin <|-- EmailSlasHandlerPlugin +EmailSlasHandlerPlugin --> EMailSender : "创建实例" +EmailSlasHandlerPlugin --> ReceiverConfig : "解析配置" +EmailSlasHandlerPlugin --> SlaSenderMessage : "读取配置" +EmailSlasHandlerPlugin --> SlaConfigMessage : "读取配置" +``` + +**代码路径** +- [EmailSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EmailSlasHandlerPlugin.java#L43-L93) +- [EMailSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-email\src\main\java\io\datavines\notification\plugin\email\EMailSender.java#L44-L45) + +## 通过配置文件或API方式管理邮件通知策略 +DataVines支持通过配置文件和API两种方式管理邮件通知策略,为用户提供灵活的配置选项。 + +**配置文件方式:** +在作业提交的JSON配置文件中,可以通过`notificationParameters`字段定义邮件通知策略。例如: + +```json +"notificationParameters": [ + { + "type": "email", + "config": { + "serverHost": "smtp.qq.com", + "serverPort": "25", + "sender": "123456@qq.com", + "enableSmtpAuth": "true", + "user": "123456@qq.com", + "passwd": "123456", + "starttlsEnable": "false", + "sslEnable": "false", + "smtpSslTrust": "true" + }, + "receiver": { + "to": "123456@qq.com" + } + } +] +``` + +**API方式:** +通过DataVines提供的REST API,可以编程方式管理邮件通知策略。主要API包括: +- 创建通知配置:POST /api/sla/notification +- 更新通知配置:PUT /api/sla/notification +- 删除通知配置:DELETE /api/sla/notification/{id} +- 查询通知配置:GET /api/sla/notification/page + +在`SlaController`类中定义了这些API端点,通过`slaNotificationService`服务处理具体的业务逻辑。 + +```mermaid +flowchart TD +A[配置源] --> B{选择方式} +B --> |配置文件| C[在JSON中定义notificationParameters] +B --> |API| D[调用REST API] +C --> E[系统解析配置] +D --> F[系统处理API请求] +E --> G[创建SlaSenderMessage] +F --> G +G --> H[创建SlaConfigMessage] +H --> I[存储配置] +I --> J[触发通知] +J --> K[结束] +``` + +**代码路径** +- [submit_job_mysql_storage.json](file://datavines-runner\src\main\resources\submit_job_mysql_storage.json#L49-L67) +- [SlaController.java](file://datavines-server\src\main\java\io\datavines\server\api\controller\SlaController.java#L211-L232) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\222\211\351\222\211\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\222\211\351\222\211\351\205\215\347\275\256.md" new file mode 100644 index 00000000..c3f0b763 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\222\211\351\222\211\351\205\215\347\275\256.md" @@ -0,0 +1,235 @@ +# 钉钉配置 + + +**本文档中引用的文件** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java) +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\ReceiverConfig.java) +- [DingTalkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkConstants.java) +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java) +- [SlaNotificationMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaNotificationMessage.java) +- [SlaConfigMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaConfigMessage.java) +- [NotificationConstants.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\constants\NotificationConstants.java) +- [io.datavines.notification.api.spi.SlasHandlerPlugin](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\resources\META-INF\plugins\io.datavines.notification.api.spi.SlasHandlerPlugin) +- [pom.xml](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\pom.xml) + + +## 目录 +1. [简介](#简介) +2. [钉钉通知渠道配置](#钉钉通知渠道配置) +3. [安全验证配置](#安全验证配置) +4. [消息模板与通知分组](#消息模板与通知分组) +5. [钉钉通知测试方法](#钉钉通知测试方法) +6. [故障排查指南](#故障排查指南) +7. [DingTalkSlasHandlerPlugin实现机制](#dingtalkslashandlerplugin实现机制) +8. [自定义扩展点](#自定义扩展点) + +## 简介 +DataVines平台提供了钉钉通知功能,允许用户通过钉钉机器人接收数据质量监控告警和通知。本文档详细说明了如何在DataVines中配置钉钉通知渠道,包括钉钉机器人Webhook URL的获取与配置、安全验证方式的设置、消息模板的自定义、通知分组策略,以及测试方法和故障排查指南。同时,文档还解释了DingTalkSlasHandlerPlugin的实现机制和扩展点,为开发者提供通过代码自定义钉钉消息格式的指导。 + +## 钉钉通知渠道配置 + +在DataVines中配置钉钉通知渠道需要设置钉钉机器人的Webhook URL和其他相关参数。这些配置通过`ReceiverConfig`类进行管理,该类定义了钉钉通知所需的所有配置项。 + +```mermaid +classDiagram +class ReceiverConfig { ++String webhook ++String secret ++String keyword ++String atMobiles ++String atDingtalkIds ++Boolean isAtAll +} +``` + +**图表来源** +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\ReceiverConfig.java#L28-L39) + +**本节来源** +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\ReceiverConfig.java#L1-L58) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L92-L119) + +### Webhook URL获取与配置 +要配置钉钉通知,首先需要在钉钉群中创建一个自定义机器人并获取Webhook URL: + +1. 在钉钉群聊天界面,点击右上角的群设置图标 +2. 选择"智能群助手" -> "添加机器人" -> "自定义" +3. 设置机器人名称和安全验证方式(见下文) +4. 复制生成的Webhook URL + +在DataVines中配置Webhook URL时,需要在通知配置界面填写以下信息: +- **webhook**: 钉钉机器人Webhook URL,必填项 +- **secret**: 加签密钥(如果启用了加签验证) +- **keyword**: 关键词(如果启用了关键词验证) +- **atMobiles**: 需要@的手机号码列表,多个号码用逗号分隔 +- **atDingtalkIds**: 需要@的钉钉用户ID列表 +- **isAtAll**: 是否@所有人,布尔值 + +## 安全验证配置 + +钉钉机器人提供了多种安全验证方式来防止未授权访问,DataVines支持以下三种安全验证方式: + +### 加签验证 +加签验证是通过HMAC-SHA256算法生成签名,确保请求来自可信来源。在DataVines中,加签验证的实现位于`DingTalkSender`类的`constructUrl`方法中。 + +```mermaid +sequenceDiagram +participant DataVines as DataVines系统 +participant DingTalk as 钉钉服务器 +DataVines->>DataVines : 生成时间戳timestamp +DataVines->>DataVines : 构造签名字符串stringToSign = timestamp + "\n" + secret +DataVines->>DataVines : 使用HMAC-SHA256算法计算签名 +DataVines->>DataVines : URL编码签名sign +DataVines->>DingTalk : 发送POST请求,URL包含timestamp和sign参数 +DingTalk->>DingTalk : 验证签名有效性 +DingTalk-->>DataVines : 返回响应结果 +``` + +**图表来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L96-L109) + +### 关键词验证 +关键词验证要求在消息内容中包含预设的关键词。在DataVines中,关键词通过`ReceiverConfig`类的`keyword`字段配置,并在`generateMsgJson`方法中添加到消息内容中。 + +### IP白名单验证 +IP白名单验证需要在钉钉机器人设置中指定允许访问的IP地址或IP段。DataVines服务器的IP地址需要添加到钉钉机器人的IP白名单中。 + +**本节来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L96-L109) +- [DingTalkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkConstants.java#L25-L27) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\entity\ReceiverConfig.java#L33) + +## 消息模板与通知分组 + +DataVines支持自定义钉钉消息模板和通知分组策略,允许用户根据不同的业务需求定制通知内容和接收对象。 + +### 消息模板 +DataVines支持两种消息类型:文本(text)和Markdown。消息模板的生成由`DingTalkSender`类的`generateMsgJson`方法实现。 + +```mermaid +flowchart TD +Start([开始]) --> CheckMsgType{消息类型} +CheckMsgType --> |文本| TextFormat["构造文本格式消息\ncontent = title + '\\n' + message"] +CheckMsgType --> |Markdown| MarkdownFormat["构造Markdown格式消息\ntext = message + '\\n\\n' + @mentions"] +TextFormat --> AddKeyword["添加关键词如果有"] +MarkdownFormat --> AddKeyword +AddKeyword --> AddAt["添加@信息\natMobiles, atDingtalkIds, isAtAll"] +AddAt --> GenerateJson["生成JSON格式消息"] +GenerateJson --> End([结束]) +``` + +**图表来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L111-L176) + +### 通知分组策略 +通知分组策略允许将不同的通知发送给不同的接收组。在DataVines中,通知分组通过`SlaConfigMessage`类的`config`字段实现,该字段存储了`ReceiverConfig`对象的JSON序列化字符串。 + +**本节来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L111-L176) +- [SlaConfigMessage.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\entity\SlaConfigMessage.java#L42) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L55-L56) + +## 钉钉通知测试方法 + +在配置完钉钉通知渠道后,建议进行测试以确保通知能够正常发送。以下是测试步骤: + +1. 在DataVines管理界面创建一个测试通知配置 +2. 填写正确的Webhook URL和安全验证信息 +3. 选择一个测试消息模板 +4. 点击"测试通知"按钮 +5. 检查钉钉群中是否收到测试消息 + +如果测试失败,可以检查DataVines日志中的错误信息。`DingTalkSender`类的`sendCardMsg`方法包含了详细的日志记录,可以帮助诊断问题。 + +**本节来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L55-L93) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L59) + +## 故障排查指南 + +当钉钉通知无法正常工作时,可以按照以下步骤进行故障排查: + +### 常见问题及解决方案 +1. **错误代码310000**: 这通常是由于加签验证失败导致的。请检查`constructUrl`方法中生成的URL是否正确包含了`sign`和`timestamp`参数。 +2. **消息发送失败**: 检查Webhook URL是否正确,以及网络连接是否正常。 +3. **无法@指定人员**: 确认`atMobiles`或`atDingtalkIds`字段中的手机号码或用户ID是否正确,且这些用户在钉钉群中。 + +### 日志分析 +查看DataVines的日志文件,重点关注`DingTalkSender`类中的日志输出。关键日志点包括: +- 消息发送前的JSON内容 +- HTTP请求的响应结果 +- 异常堆栈信息 + +**本节来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L77-L81) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L80-L82) + +## DingTalkSlasHandlerPlugin实现机制 + +`DingTalkSlasHandlerPlugin`是DataVines钉钉通知功能的核心实现类,它实现了`SlasHandlerPlugin`接口,负责处理SLA(Service Level Agreement)通知的发送。 + +```mermaid +classDiagram +class SlasHandlerPlugin { ++notify(SlaNotificationMessage, Map>) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +class DingTalkSlasHandlerPlugin { ++notify(SlaNotificationMessage, Map>) SlaNotificationResult ++getConfigSenderJson() String ++getConfigJson() String +} +DingTalkSlasHandlerPlugin --|> SlasHandlerPlugin : 实现 +DingTalkSlasHandlerPlugin --> DingTalkSender : 使用 +DingTalkSlasHandlerPlugin --> ReceiverConfig : 使用 +``` + +**图表来源** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L39) +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java#L29) + +### 核心方法 +`DingTalkSlasHandlerPlugin`类实现了三个核心方法: +- `notify`: 处理通知消息的发送,遍历所有钉钉发送者配置,调用`DingTalkSender`发送消息 +- `getConfigJson`: 返回钉钉通知配置的JSON格式,定义了配置界面的表单字段 +- `getConfigSenderJson`: 返回发送者配置的JSON格式 + +**本节来源** +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L42-L132) +- [SlasHandlerPlugin.java](file://datavines-notification\datavines-notification-api\src\main\java\io\datavines\notification\api\spi\SlasHandlerPlugin.java#L36-L40) + +## 自定义扩展点 + +DataVines的钉钉通知功能设计为可扩展的,开发者可以通过以下方式自定义钉钉消息格式: + +### SPI机制 +DataVines使用SPI(Service Provider Interface)机制加载通知插件。在`META-INF/plugins/io.datavines.notification.api.spi.SlasHandlerPlugin`文件中注册了钉钉插件: + +``` +dingtalk=io.datavines.notification.plugin.dingtalk.DingTalkSlasHandlerPlugin +``` + +### 自定义消息格式 +要自定义钉钉消息格式,可以继承`DingTalkSender`类并重写`generateMsgJson`方法,或者创建一个新的`SlasHandlerPlugin`实现。 + +```mermaid +flowchart TD +A[开始] --> B[创建自定义SlasHandlerPlugin] +B --> C[实现notify方法] +C --> D[创建自定义消息生成器] +D --> E[重写generateMsgJson方法] +E --> F[注册SPI服务] +F --> G[部署插件JAR] +G --> H[在DataVines中使用] +``` + +**图表来源** +- [io.datavines.notification.api.spi.SlasHandlerPlugin](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\resources\META-INF\plugins\io.datavines.notification.api.spi.SlasHandlerPlugin#L1) +- [pom.xml](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\pom.xml#L30) + +**本节来源** +- [DingTalkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSender.java#L111-L176) +- [DingTalkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\java\io\datavines\notification\plugin\dingtalk\DingTalkSlasHandlerPlugin.java#L89-L132) +- [io.datavines.notification.api.spi.SlasHandlerPlugin](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-dingtalk\src\main\resources\META-INF\plugins\io.datavines.notification.api.spi.SlasHandlerPlugin#L1) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\243\236\344\271\246\351\205\215\347\275\256.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\243\236\344\271\246\351\205\215\347\275\256.md" new file mode 100644 index 00000000..f1638ec0 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\200\232\347\237\245\351\205\215\347\275\256/\351\243\236\344\271\246\351\205\215\347\275\256.md" @@ -0,0 +1,265 @@ +# 飞书配置 + + +**本文档中引用的文件** +- [LarkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSlasHandlerPlugin.java) +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java) +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\entity\ReceiverConfig.java) +- [LarkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkConstants.java) +- [CardDTO.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\entity\CardDTO.java) +- [GroupCardDTO.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\entity\GroupCardDTO.java) +- [MessageDTO.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\entity\MessageDTO.java) +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java) + + +## 目录 +1. [引言](#引言) +2. [飞书通知渠道配置](#飞书通知渠道配置) +3. [安全验证机制](#安全验证机制) +4. [消息卡片模板定制](#消息卡片模板定制) +5. [富文本消息格式支持](#富文本消息格式支持) +6. [测试流程和故障排查](#测试流程和故障排查) +7. [LarkSlasHandlerPlugin实现细节](#larkslashandlerplugin实现细节) +8. [高级消息交互功能](#高级消息交互功能) + +## 引言 +DataVines支持通过飞书机器人发送数据质量告警通知。本文档详细说明如何配置飞书通知渠道,包括Webhook URL配置、安全验证、消息模板定制和高级交互功能。飞书通知通过LarkSlasHandlerPlugin实现,利用飞书开放平台API发送交互式消息卡片。 + +## 飞书通知渠道配置 +在DataVines中配置飞书通知渠道需要设置飞书机器人Webhook URL和相关参数。配置主要通过LarkSlasHandlerPlugin类实现,该插件定义了飞书通知所需的配置参数。 + +飞书通知配置包含以下关键参数: +- **webhook**: 飞书群机器人的Webhook URL,用于发送消息 +- **atAll**: 布尔值,指示是否@所有人 + +配置过程通过getConfigJson方法定义表单参数,用户在DataVines UI中填写这些参数来完成配置。 + +```mermaid +flowchart TD +Start([开始配置]) --> WebhookConfig["配置Webhook URL"] +WebhookConfig --> AtAllConfig["设置@所有人选项"] +AtAllConfig --> Validation["验证配置"] +Validation --> Save["保存配置"] +Save --> End([配置完成]) +``` + +**节来源** +- [LarkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSlasHandlerPlugin.java#L100-L131) + +## 安全验证机制 +DataVines的飞书通知实现中,安全验证主要依赖于飞书机器人Webhook URL的保密性。Webhook URL是飞书机器人与外部系统通信的唯一凭证,必须妥善保管。 + +飞书平台本身提供了以下安全机制: +1. Webhook URL包含唯一标识符,难以猜测 +2. 可以在飞书管理后台随时重置Webhook URL +3. 支持IP白名单限制访问来源 + +在DataVines中,Webhook URL作为敏感信息存储,建议通过安全的配置管理方式维护。 + +```mermaid +graph TB +subgraph "飞书平台" +Security[安全机制] +WebhookURL[Webhook URL保密] +Reset[URL重置功能] +IPWhitelist[IP白名单] +end +subgraph "DataVines" +Config[配置管理] +Storage[安全存储] +Access[访问控制] +end +Config --> WebhookURL +Security --> WebhookURL +``` + +**节来源** +- [ReceiverConfig.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\entity\ReceiverConfig.java#L26-L37) + +## 消息卡片模板定制 +DataVines使用飞书交互式卡片(Interactive Card)格式发送通知,提供了高度可定制的消息模板。消息卡片由CardDTO基类和GroupCardDTO子类实现。 + +消息卡片结构包括: +- **Header**: 卡片头部,包含标题和颜色 +- **Elements**: 卡片元素列表,包含消息内容 + +默认消息模板包含以下字段: +- **摘要**: 告警主题 +- **详情**: 告警详细信息 +- **请留意**: 当@所有人时显示的提示 + +可以通过修改LarkSender类中的常量来自定义模板: + +```mermaid +erDiagram +CARD_DTO { +string headerContent +string headerColor +list elements +} +HEADER_DTO { +string template +object title +} +ELEMENT_DTO { +object text +string tag +} +TEXT_DTO { +string content +string tag +} +CARD_DTO ||--o{ HEADER_DTO : contains +CARD_DTO ||--o{ ELEMENT_DTO : contains +ELEMENT_DTO ||--|| TEXT_DTO : contains +``` + +**节来源** +- [CardDTO.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\entity\CardDTO.java#L25-L49) +- [GroupCardDTO.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\entity\GroupCardDTO.java#L24-L36) + +## 富文本消息格式支持 +DataVines的飞书通知支持富文本格式,通过飞书的lark_md标签实现。消息内容使用Markdown语法,支持以下格式: + +- **粗体**: 使用**文本**表示 +- 换行: 使用\n表示 +- @提及: 使用语法 + +在LarkSender的sendCardMsg方法中,消息被格式化为包含多个MessageDTO对象的列表,每个对象代表卡片中的一个消息块。系统预定义了多种消息构建器: + +- **routineBuilder**: 普通消息构建器 +- **atAllBuilder**: @所有人消息构建器 +- **atListBuilder**: @指定用户列表构建器 + +消息通过ContentUtil.createParamMap方法转换为飞书API所需的参数格式,其中包含消息类型和卡片内容。 + +```mermaid +flowchart TD +Message["原始消息内容"] --> Format["格式化处理"] +Format --> Markdown["转换为lark_md格式"] +Markdown --> Elements["创建消息元素"] +Elements --> Card["构建卡片对象"] +Card --> JSON["序列化为JSON"] +JSON --> Send["发送到飞书"] +``` + +**节来源** +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java#L50-L84) +- [MessageDTO.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\entity\MessageDTO.java#L40-L56) + +## 测试流程和故障排查 +### 测试流程 +1. 在飞书创建群机器人并获取Webhook URL +2. 在DataVines中配置飞书通知渠道 +3. 触发数据质量检查规则 +4. 验证飞书群组中是否收到告警消息 + +### 故障排查 +常见问题及解决方案: + +| 问题现象 | 可能原因 | 解决方案 | +|---------|---------|---------| +| 无法发送消息 | Webhook URL错误 | 验证Webhook URL是否正确 | +| 消息格式异常 | JSON序列化错误 | 检查CardDTO对象结构 | +| 部分接收者未收到 | 网络请求失败 | 检查网络连接和防火墙设置 | +| @所有人无效 | atAll参数未设置 | 确认atAll配置为true | + +日志排查要点: +- 检查LarkSender中的错误日志 +- 验证HttpUtils.post请求的返回结果 +- 确认ReceiverConfig配置的完整性 + +```mermaid +graph TD +Issue[问题发生] --> CheckConfig["检查配置"] +CheckConfig --> ValidateWebhook["验证Webhook URL"] +ValidateWebhook --> TestConnection["测试连接"] +TestConnection --> AnalyzeLog["分析日志"] +AnalyzeLog --> FixIssue["解决问题"] +FixIssue --> Verify["验证修复"] +Verify --> End([问题解决]) +``` + +**节来源** +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java#L58-L78) +- [NotificationManager.java](file://datavines-notification\datavines-notification-core\src\main\java\io\datavines\notification\core\NotificationManager.java#L45-L68) + +## LarkSlasHandlerPlugin实现细节 +LarkSlasHandlerPlugin是飞书通知的核心实现类,实现了SlasHandlerPlugin接口。该插件负责处理飞书通知的配置和发送逻辑。 + +主要方法包括: +- **notify**: 发送通知的核心方法,处理SlaNotificationMessage并发送到配置的接收者 +- **getConfigJson**: 返回飞书通知渠道的配置表单定义 +- **getConfigSenderJson**: 返回发送者配置(当前为空) + +notify方法的执行流程: +1. 过滤出类型为"lark"的通知渠道 +2. 遍历每个飞书发送者配置 +3. 解析接收者配置为ReceiverConfig对象 +4. 调用LarkSender发送卡片消息 +5. 收集发送结果并返回 + +插件通过Java SPI机制注册,在META-INF/plugins/io.datavines.notification.api.spi.SlasHandlerPlugin文件中声明。 + +```mermaid +sequenceDiagram +participant DataVines as DataVines系统 +participant Plugin as LarkSlasHandlerPlugin +participant Sender as LarkSender +participant Feishu as 飞书平台 +DataVines->>Plugin : notify(message, config) +Plugin->>Plugin : 过滤lark类型渠道 +loop 每个发送者 +Plugin->>Plugin : 解析接收者配置 +Plugin->>Sender : sendCardMsg() +Sender->>Sender : 构建消息卡片 +Sender->>Feishu : HTTP POST请求 +Feishu-->>Sender : 响应结果 +Sender-->>Plugin : 返回发送结果 +end +Plugin-->>DataVines : 返回汇总结果 +``` + +**节来源** +- [LarkSlasHandlerPlugin.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSlasHandlerPlugin.java#L39-L75) + +## 高级消息交互功能 +DataVines通过飞书开放平台API实现了高级消息交互功能,主要基于交互式卡片(Interactive Card)实现。虽然当前实现主要侧重于消息发送,但飞书API支持以下高级功能: + +### 潜在的高级功能扩展 +1. **按钮交互**: 在卡片中添加操作按钮,如"确认已处理"、"查看详情"等 +2. **多级菜单**: 提供更复杂的消息交互界面 +3. **消息更新**: 更新已发送的消息内容 +4. **用户身份验证**: 通过open_id识别用户身份 + +### API调用机制 +系统通过以下API端点与飞书平台交互: +- **/bot/v2/hook/%s**: 发送群机器人消息 +- **/auth/v3/tenant_access_token/internal**: 获取租户访问令牌 +- **/contact/v3/users/batch_get_id**: 批量获取用户open_id +- **/im/v1/messages**: 发送单聊消息 + +当前实现使用Webhook方式发送消息,未来可扩展为使用访问令牌的API调用方式,以支持更丰富的交互功能。 + +```mermaid +graph TB +subgraph "DataVines" +Plugin[LarkSlasHandlerPlugin] +Sender[LarkSender] +end +subgraph "飞书API" +Webhook[Webhook API] +AuthAPI[认证API] +UserAPI[用户API] +MessageAPI[消息API] +end +Plugin --> Sender +Sender --> Webhook +Sender --> AuthAPI +Sender --> UserAPI +Sender --> MessageAPI +``` + +**节来源** +- [LarkConstants.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkConstants.java#L26-L35) +- [LarkSender.java](file://datavines-notification\datavines-notification-plugins\datavines-notification-plugin-lark\src\main\java\io\datavines\notification\plugin\lark\LarkSender.java#L66-L67) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\205\215\347\275\256\350\257\264\346\230\216.md" "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\205\215\347\275\256\350\257\264\346\230\216.md" new file mode 100644 index 00000000..6ce522f9 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\205\215\347\275\256\350\257\264\346\230\216/\351\205\215\347\275\256\350\257\264\346\230\216.md" @@ -0,0 +1,267 @@ +# 配置说明 + + +**本文档引用的文件** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [datavines.yaml](file://deploy/k8s/datavines.yaml) +- [jmx_exporter_config.yaml](file://datavines-server/src/main/resources/jmx/jmx_exporter_config.yaml) +- [Config.java](file://datavines-common/src/main/java/io/datavines/common/config/Config.java) +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java) +- [Configurations.java](file://datavines-common/src/main/java/io/datavines/common/config/Configurations.java) +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心配置](#核心配置) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录)(如有必要) + +## 简介 +DataVines是一个数据质量监控和验证平台,提供全面的配置选项来满足不同环境和需求。本配置说明文档旨在全面介绍DataVines的所有配置选项,按模块组织包括服务器配置、数据库配置、执行引擎配置、通知配置等。文档将为每个配置项提供详细的说明,包括其作用、可选值、默认值和影响范围,解释配置文件的加载顺序和优先级规则,提供配置的最佳实践和常见配置模式,包含敏感信息(如密码)的安全存储建议,并为高级用户提供性能相关配置的调优指导。 + +## 项目结构 +DataVines项目的配置文件分布在多个模块中,主要配置文件位于`datavines-server`模块的`src/main/resources`目录下。核心配置包括`application.yaml`(主配置文件)、`common.properties`(通用配置)和`jmx/jmx_exporter_config.yaml`(JMX监控配置)。部署相关的配置文件位于`deploy`目录下,包括`compose/docker-compose.yaml`(Docker部署配置)和`k8s/datavines.yaml`(Kubernetes部署配置)。配置相关的代码主要位于`datavines-common`模块的`config`包中。 + +```mermaid +graph TD +A[配置文件] --> B[datavines-server] +A --> C[datavines-common] +A --> D[deploy] +B --> E[application.yaml] +B --> F[jmx_exporter_config.yaml] +C --> G[common.properties] +D --> H[docker-compose.yaml] +D --> I[datavines.yaml] +``` + +**图源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [datavines.yaml](file://deploy/k8s/datavines.yaml) +- [jmx_exporter_config.yaml](file://datavines-server/src/main/resources/jmx/jmx_exporter_config.yaml) + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [datavines.yaml](file://deploy/k8s/datavines.yaml) + +## 核心配置 +DataVines的核心配置主要分为服务器配置、数据库配置、执行引擎配置和通知配置等模块。`application.yaml`文件是主要的配置文件,使用Spring Boot的配置机制,支持多环境配置(如通过`---`分隔符定义的MySQL配置)。`common.properties`文件包含注册中心等通用配置。配置系统通过`Config`类和`Configurations`类提供统一的配置访问接口,支持字符串、整数、布尔值、浮点数和长整型等多种数据类型的获取。 + +**章节来源** +- [Config.java](file://datavines-common/src/main/java/io/datavines/common/config/Config.java) +- [Configurations.java](file://datavines-common/src/main/java/io/datavines/common/config/Configurations.java) +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [common.properties](file://datavines-common/src/main/resources/common.properties) + +## 架构概述 +DataVines的配置架构采用分层设计,从外部部署配置到内部代码配置形成完整的配置体系。外部部署通过Docker Compose或Kubernetes配置环境变量,这些变量可以覆盖`application.yaml`中的配置。`application.yaml`作为主配置文件,定义了服务器、数据库、Quartz调度等核心组件的配置。`common.properties`提供注册中心等跨模块的通用配置。代码层面,`Config`和`Configurations`类提供了统一的配置访问接口,而`PluginLoader`机制支持插件化配置的动态加载。 + +```mermaid +graph TD +A[外部部署配置] --> B[Docker/K8s环境变量] +B --> C[application.yaml] +C --> D[common.properties] +D --> E[代码配置] +E --> F[Config类] +E --> G[Configurations类] +E --> H[PluginLoader] +F --> I[配置访问接口] +G --> I +H --> J[插件配置] +``` + +**图源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [common.properties](file://datavines-common/src/main/resources/common.properties) +- [docker-compose.yaml](file://deploy/compose/docker-compose.yaml) +- [datavines.yaml](file://deploy/k8s/datavines.yaml) +- [Config.java](file://datavines-common/src/main/java/io/datavines/common/config/Config.java) +- [Configurations.java](file://datavines-common/src/main/java/io/datavines/common/config/Configurations.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +## 详细组件分析 +### 服务器配置分析 +服务器配置主要在`application.yaml`文件中定义,包括端口、应用名称、MVC路径匹配策略等。服务器端口通过`server.port`配置,默认值为5600。应用名称通过`spring.application.name`配置,用于服务注册和监控。MVC路径匹配策略通过`spring.mvc.pathmatch.matching-strategy`配置,使用`ant_path_matcher`策略。管理端点通过`management.endpoints.web.exposure.include`配置,暴露所有端点以便监控。 + +#### 服务器配置类图 +```mermaid +classDiagram +class ServerConfig { ++int port ++String applicationName ++String pathMatchingStrategy ++String[] exposedEndpoints +} +class ManagementConfig { ++Map~String, Object~ metricsTags ++LoggingConfig loggingConfig +} +class LoggingConfig { ++String configLocation +} +ServerConfig --> ManagementConfig : "包含" +ManagementConfig --> LoggingConfig : "包含" +``` + +**图源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +### 数据库配置分析 +数据库配置是DataVines的核心配置之一,支持多种数据库类型。主配置文件`application.yaml`中定义了数据源的驱动类名、URL、用户名和密码,以及Hikari连接池的详细配置。通过Spring Profiles支持多环境配置,如PostgreSQL和MySQL的切换。Quartz调度器的数据库配置也在此定义,支持JDBC存储类型和集群模式。 + +#### 数据库配置序列图 +```mermaid +sequenceDiagram +participant App as "应用程序" +participant Spring as "Spring Boot" +participant Hikari as "HikariCP" +participant DB as "数据库" +App->>Spring : 启动应用 +Spring->>Spring : 加载application.yaml +Spring->>Hikari : 创建数据源 +Hikari->>Hikari : 配置连接池参数 +Hikari->>DB : 建立数据库连接 +DB-->>Hikari : 连接成功 +Hikari-->>Spring : 返回数据源 +Spring-->>App : 应用启动完成 +``` + +**图源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) + +### 执行引擎配置分析 +执行引擎配置通过`EnvConfig`类和`DataVinesJobConfig`类实现,支持批处理和流处理模式。`EnvConfig`定义了执行引擎的类型和具体配置,而`DataVinesJobConfig`则包含了作业的名称、环境配置、数据源、转换和接收器等完整配置。配置解析通过`ConfigParser`类完成,使用`PluginLoader`机制动态加载执行环境。 + +#### 执行引擎配置流程图 +```mermaid +flowchart TD +Start([开始]) --> LoadConfig["加载配置文件"] +LoadConfig --> ParseConfig["解析配置"] +ParseConfig --> CreateEnv["创建运行环境"] +CreateEnv --> LoadPlugins["加载插件"] +LoadPlugins --> ValidateConfig["验证配置"] +ValidateConfig --> ConfigValid{"配置有效?"} +ConfigValid --> |是| ReturnEnv["返回运行环境"] +ConfigValid --> |否| ThrowError["抛出异常"] +ThrowError --> End([结束]) +ReturnEnv --> End +``` + +**图源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +**章节来源** +- [DataVinesJobConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java) +- [EnvConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/EnvConfig.java) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +### 通知配置分析 +通知配置通过插件化机制实现,支持多种通知渠道如钉钉、邮件、飞书和企业微信。配置主要在`datavines-notification-plugins`模块中定义,通过SPI机制动态加载。通知配置的加载和管理由`NotificationManager`类负责,确保通知服务的可扩展性和灵活性。 + +**章节来源** +- [datavines-notification-plugins](file://datavines-notification/datavines-notification-plugins) + +### 敏感信息安全管理 +DataVines对敏感信息如数据库密码提供了专门的安全管理机制。`SensitiveDataConverter`类和`SensitiveLogUtils`类负责在日志输出时对敏感数据进行脱敏处理,使用正则表达式匹配密码字段并将其替换为星号。这种机制确保了敏感信息不会在日志中明文显示,提高了系统的安全性。 + +#### 敏感信息处理流程图 +```mermaid +flowchart TD +Start([日志记录]) --> CheckSensitive["检查敏感数据"] +CheckSensitive --> HasPassword{"包含密码?"} +HasPassword --> |是| MaskPassword["替换为星号"] +HasPassword --> |否| KeepOriginal["保持原样"] +MaskPassword --> OutputLog["输出日志"] +KeepOriginal --> OutputLog +OutputLog --> End([完成]) +``` + +**图源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java) + +**章节来源** +- [SensitiveDataConverter.java](file://datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java) +- [SensitiveLogUtils.java](file://datavines-common/src/main/java/io/datavines/common/utils/SensitiveLogUtils.java) + +## 依赖分析 +DataVines的配置系统依赖于多个核心组件和外部库。Spring Boot框架提供了基础的配置管理能力,包括YAML配置文件解析、环境变量支持和Profile机制。HikariCP作为高性能的数据库连接池,其配置参数直接影响数据库性能。Quartz调度器的配置依赖于数据库存储,支持集群模式下的任务调度。SPI机制(`PluginLoader`)实现了插件化配置的动态加载,提高了系统的可扩展性。 + +```mermaid +graph TD +A[配置系统] --> B[Spring Boot] +A --> C[HikariCP] +A --> D[Quartz] +A --> E[SPI机制] +B --> F[YAML解析] +B --> G[环境变量] +B --> H[Profile支持] +C --> I[连接池配置] +D --> J[任务调度] +E --> K[插件加载] +``` + +**图源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) + +## 性能考虑 +在配置方面,DataVines提供了多个性能相关的配置选项。数据库连接池的配置(如`maximum-pool-size`、`minimum-idle`)直接影响数据库访问性能。Quartz调度器的线程池大小(`org.quartz.threadPool.threadCount`)影响任务调度的并发能力。日志配置中的`log.cache.row.num`和`log.flush.interval`参数影响日志输出性能。对于高级用户,建议根据实际负载调整这些参数以优化系统性能。 + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java) + +## 故障排除指南 +配置相关的问题通常表现为应用启动失败、数据库连接异常或任务执行错误。检查`application.yaml`文件的语法是否正确,特别是缩进和冒号的使用。验证数据库连接参数是否正确,包括URL、用户名和密码。确认Spring Profile是否正确激活,特别是在使用Docker或Kubernetes部署时。查看日志文件中的错误信息,通常会提供具体的配置错误原因。 + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [ConfigParser.java](file://datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java) + +## 结论 +DataVines提供了一套完整且灵活的配置系统,支持从服务器设置到执行引擎的全面配置。通过分层的配置架构和插件化机制,系统能够适应不同的部署环境和业务需求。合理的配置不仅能够确保系统稳定运行,还能优化性能和安全性。用户应根据具体需求仔细配置各项参数,并遵循最佳实践来管理配置文件。 + +## 附录 +### 配置项参考表 +| 配置项 | 作用 | 可选值 | 默认值 | 影响范围 | +|-------|------|-------|-------|--------| +| server.port | 服务器端口 | 1-65535 | 5600 | 服务器 | +| spring.datasource.url | 数据库连接URL | JDBC URL | jdbc:postgresql://127.0.0.1:5432/datavines | 数据库 | +| spring.datasource.maximum-pool-size | 连接池最大大小 | 正整数 | 50 | 数据库性能 | +| org.quartz.threadPool.threadCount | 调度器线程数 | 正整数 | 25 | 任务调度性能 | +| log.cache.row.num | 日志缓存行数 | 正整数 | 64 | 日志性能 | + +**章节来源** +- [application.yaml](file://datavines-server/src/main/resources/application.yaml) +- [CoreConfig.java](file://datavines-common/src/main/java/io/datavines/common/config/CoreConfig.java) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\241\271\347\233\256\346\246\202\350\277\260.md" "b/.qoder/repowiki/zh/content/\351\241\271\347\233\256\346\246\202\350\277\260.md" new file mode 100644 index 00000000..913c6f13 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\241\271\347\233\256\346\246\202\350\277\260.md" @@ -0,0 +1,278 @@ +# 项目概述 + + +**本文档中引用的文件** +- [README.md](file://README.md) +- [pom.xml](file://pom.xml) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java) +- [CommonConstants.java](file://datavines-common/src/main/java/io/datavines/common/CommonConstants.java) +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java) +- [datavines-mysql.sql](file://scripts/sql/datavines-mysql.sql) +- [MetricDimension.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricDimension.java) +- [MetricValidator.java](file://datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java) + + +## 目录 +1. [引言](#引言) +2. [项目背景与设计目标](#项目背景与设计目标) +3. [核心功能特性](#核心功能特性) +4. [系统架构设计](#系统架构设计) +5. [技术栈与组件](#技术栈与组件) +6. [微内核与SPI插件机制](#微内核与spi插件机制) +7. [与其他数据质量管理工具的对比](#与其他数据质量管理工具的对比) +8. [适用场景](#适用场景) +9. [结论](#结论) + +## 引言 + +DataVines是一个易于使用的数据质量服务平台,旨在确保数据在集成和处理过程中的准确性,是DataOps的核心组件。该平台支持多种度量标准,提供全面的数据质量管理解决方案,包括数据目录、数据质量检查、数据画像等功能。通过插件化设计和灵活的执行模式,DataVines能够适应各种复杂的数据环境,为用户提供高效、可靠的数据质量保障。 + +**Section sources** +- [README.md](file://README.md#L24-L25) + +## 项目背景与设计目标 + +随着大数据技术的发展,数据质量成为企业数字化转型中的关键问题。低质量的数据可能导致决策失误、业务损失和客户信任度下降。传统的数据质量管理工具往往功能单一、扩展性差,难以满足现代企业对数据质量的高要求。DataVines应运而生,旨在解决这些问题,提供一个全面、灵活、易用的数据质量服务平台。 + +DataVines的设计目标包括: +- **易用性**:提供直观的Web界面,用户可以轻松配置和管理数据质量检查任务。 +- **灵活性**:支持多种数据源和执行引擎,用户可以根据需求选择合适的配置。 +- **可扩展性**:采用微内核架构和SPI插件机制,方便用户自定义扩展功能。 +- **高可用性**:支持水平扩展和自动故障转移,确保系统的稳定性和可靠性。 +- **高性能**:优化数据处理流程,提高数据质量检查的效率。 + +**Section sources** +- [README.md](file://README.md#L24-L25) + +## 核心功能特性 + +### 数据目录 + +DataVines的数据目录功能定期获取数据源的元数据,构建数据目录,并监控元数据的变化。用户可以通过标签管理功能对元数据进行分类和标注,便于数据的查找和管理。 + +- **定期获取数据源元数据**,构建数据目录 +- **定期监控元数据变化** +- **支持标签管理**,便于元数据的分类和标注 + +**Section sources** +- [README.md](file://README.md#L37-L42) + +### 数据质量 + +DataVines内置了27种数据质量检查规则,支持4种数据质量检查规则类型,包括单表列检查、单表自定义SQL检查、跨表准确性检查和两表值比较检查。用户可以设置定时任务进行数据质量检查,并通过SLA(服务水平协议)对检查结果进行告警。 + +- **内置27种数据质量检查规则** +- **支持4种数据质量检查规则类型** + - 单表列检查 + - 单表自定义SQL检查 + - 跨表准确性检查 + - 两表值比较检查 +- **支持定时任务**,定期执行数据质量检查 +- **支持SLA**,对检查结果进行告警 + +**Section sources** +- [README.md](file://README.md#L47-L54) + +### 数据画像 + +DataVines支持定时执行数据检测,生成数据画像报告。平台能够自动识别列类型,匹配相应的数据画像指标,支持表行数趋势监控和数据分布视图。 + +- **支持定时执行数据检测**,生成数据画像报告 +- **支持自动识别列类型**,匹配相应的数据画像指标 +- **支持表行数趋势监控** +- **支持数据分布视图** + +**Section sources** +- [README.md](file://README.md#L58-L63) + +### 插件设计 + +DataVines基于插件化设计,多个模块支持用户自定义插件扩展,包括数据源、检查规则、作业执行引擎、告警通道、错误数据存储和注册中心。 + +- **数据源**:已支持MySQL、Impala、StarRocks、Doris、Presto、Trino、ClickHouse、PostgreSQL等 +- **检查规则**:内置27种检查规则,如空值检查、非空检查、枚举检查等 +- **作业执行引擎**:支持Spark和Local两种执行引擎,Spark引擎目前仅支持Spark 2.4版本,Local引擎基于JDBC开发,无需依赖其他执行引擎 +- **告警通道**:支持Email +- **错误数据存储**:支持MySQL和本地文件(仅Local执行引擎支持) +- **注册中心**:支持MySQL、PostgreSQL和ZooKeeper + +**Section sources** +- [README.md](file://README.md#L67-L76) + +### 多种执行模式 + +DataVines提供Web页面配置检查任务,运行任务,查看任务执行日志、错误数据和检查结果。同时支持在线生成任务运行脚本,通过`datavines-submit.sh`提交任务,可与调度系统结合使用。 + +- **提供Web页面**,配置和管理检查任务 +- **支持在线生成任务运行脚本**,通过`datavines-submit.sh`提交任务 +- **可与调度系统结合使用** + +**Section sources** +- [README.md](file://README.md#L78-L82) + +### 易于部署与高可用 + +DataVines依赖较少,易于部署。最小化部署仅需依赖MySQL即可启动项目,完成数据质量检查操作。支持水平扩展和自动故障转移,确保任务不丢失或重复。 + +- **依赖较少**,易于部署 +- **最小化部署仅需依赖MySQL** +- **支持水平扩展**,自动故障转移 +- **去中心化设计**,Server节点支持水平扩展以提高性能 +- **任务自动故障转移**,确保任务不丢失或重复 + +**Section sources** +- [README.md](file://README.md#L85-L91) + +## 系统架构设计 + +DataVines的系统架构设计遵循微内核原则,核心组件包括数据目录、数据质量检查、数据画像、插件管理、任务调度和注册中心。各组件通过插件化设计实现高度解耦,支持灵活扩展。 + +```mermaid +graph TB +subgraph "前端" +UI[用户界面] +Router[路由] +end +subgraph "后端" +API[API服务器] +Auth[认证服务] +DB[(数据库)] +end +UI --> API +API --> Auth +API --> DB +``` + +**Diagram sources** +- [README.md](file://README.md#L27) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L48-L50) + +## 技术栈与组件 + +### 后端技术栈 + +DataVines后端采用Spring Boot框架,结合MyBatis-Plus进行数据库操作,使用Swagger生成API文档。核心组件包括数据目录、数据质量检查、数据画像、插件管理、任务调度和注册中心。 + +- **Spring Boot**:提供快速开发和部署能力 +- **MyBatis-Plus**:简化数据库操作 +- **Swagger**:生成API文档 +- **HikariCP**:高性能数据库连接池 +- **Quartz**:任务调度 +- **Druid**:数据库监控 + +**Section sources** +- [pom.xml](file://pom.xml#L87-L88) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L48-L50) + +### 前端技术栈 + +DataVines前端采用React框架,结合Ant Design UI库,提供丰富的用户界面组件。使用Redux进行状态管理,Axios进行HTTP请求,Webpack进行构建。 + +- **React**:构建用户界面 +- **Ant Design**:提供丰富的UI组件 +- **Redux**:状态管理 +- **Axios**:HTTP请求 +- **Webpack**:构建工具 + +**Section sources** +- [package.json](file://datavines-ui/package.json) +- [webpack.common.js](file://datavines-ui/build/webpack.common.js#L130-L137) + +### 计算引擎支持 + +DataVines支持多种计算引擎,包括Spark和Flink。用户可以根据需求选择合适的计算引擎,提高数据处理的效率。 + +- **Spark**:支持Spark 2.4版本 +- **Flink**:支持Flink引擎 + +**Section sources** +- [README.md](file://README.md#L73-L74) + +## 微内核与SPI插件机制 + +### 微内核架构 + +DataVines采用微内核架构,核心组件负责基本功能,扩展功能通过插件实现。这种设计使得系统更加灵活,易于维护和扩展。 + +- **核心组件**:负责基本功能,如数据目录、数据质量检查、数据画像等 +- **插件组件**:负责扩展功能,如数据源、检查规则、作业执行引擎等 + +**Section sources** +- [README.md](file://README.md#L67-L76) + +### SPI插件机制 + +DataVines使用SPI(Service Provider Interface)插件机制,通过`@SPI`注解定义插件接口,`PluginLoader`类负责加载和管理插件实例。插件配置文件位于`META-INF/plugins`目录下,按接口全名命名。 + +```mermaid +classDiagram +class SPI { ++String value() default "" +} +class PluginLoader { ++static PluginLoader getPluginLoader(Class type) ++T getOrCreatePlugin(String name) ++Map> getPluginClasses() ++void loadDirectory(Map> pluginClasses, String type) +} +SPI <|-- PluginLoader : "使用" +``` + +**Diagram sources** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L28-L31) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L75-L407) + +### 插件加载流程 + +1. **定义插件接口**:使用`@SPI`注解标记接口 +2. **实现插件**:实现插件接口的具体类 +3. **配置插件**:在`META-INF/plugins`目录下创建配置文件,格式为`接口全名=插件实现类全名` +4. **加载插件**:通过`PluginLoader`类加载插件实例 + +**Section sources** +- [SPI.java](file://datavines-spi/src/main/java/io/datavines/spi/SPI.java#L28-L31) +- [PluginLoader.java](file://datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java#L75-L407) + +## 与其他数据质量管理工具的对比 + +| 特性 | DataVines | 其他工具A | 其他工具B | +| --- | --- | --- | --- | +| **易用性** | 提供直观的Web界面,易于配置和管理 | 界面复杂,学习成本高 | 界面简洁,但功能有限 | +| **灵活性** | 支持多种数据源和执行引擎,插件化设计 | 固定数据源,扩展性差 | 支持部分数据源,扩展性一般 | +| **可扩展性** | 微内核架构,SPI插件机制 | 无插件机制,难以扩展 | 插件机制简单,扩展性有限 | +| **高可用性** | 支持水平扩展和自动故障转移 | 单点故障,可靠性低 | 支持集群,但故障转移机制不完善 | +| **高性能** | 优化数据处理流程,提高检查效率 | 处理速度慢,资源消耗大 | 处理速度较快,但资源消耗较高 | + +**Section sources** +- [README.md](file://README.md#L24-L91) + +## 适用场景 + +### 企业数据治理 + +DataVines适用于企业数据治理,帮助企业在数据集成和处理过程中确保数据的准确性。通过数据目录、数据质量检查和数据画像功能,企业可以全面了解和管理数据资产,提高数据质量。 + +### 数据仓库建设 + +在数据仓库建设过程中,DataVines可以作为数据质量检查工具,确保数据仓库中的数据符合预期标准。通过定时任务和SLA告警,及时发现和修复数据质量问题。 + +### 数据湖管理 + +DataVines支持多种数据源,适用于数据湖管理。通过插件化设计,可以轻松集成新的数据源,确保数据湖中的数据质量。 + +### 实时数据处理 + +DataVines支持Spark和Flink等实时计算引擎,适用于实时数据处理场景。通过实时数据质量检查,确保实时数据的准确性和一致性。 + +**Section sources** +- [README.md](file://README.md#L24-L91) + +## 结论 + +DataVines作为一个全面的数据质量服务平台,通过微内核架构和SPI插件机制,提供了高度的灵活性和可扩展性。其核心功能包括数据目录、数据质量检查、数据画像等,支持多种数据源和计算引擎,适用于企业数据治理、数据仓库建设、数据湖管理和实时数据处理等多种场景。通过与其他数据质量管理工具的对比,可以看出DataVines在易用性、灵活性、可扩展性、高可用性和高性能方面具有明显优势。未来,DataVines将继续优化现有功能,增加更多数据源和计算引擎的支持,为用户提供更加全面和高效的数据质量解决方案。 + +**Section sources** +- [README.md](file://README.md#L24-L91) +- [pom.xml](file://pom.xml#L26-L29) +- [DataVinesServer.java](file://datavines-server/src/main/java/io/datavines/server/DataVinesServer.java#L48-L50) \ No newline at end of file diff --git a/.qoder/repowiki/zh/meta/repowiki-metadata.json b/.qoder/repowiki/zh/meta/repowiki-metadata.json new file mode 100644 index 00000000..f3ceb636 --- /dev/null +++ b/.qoder/repowiki/zh/meta/repowiki-metadata.json @@ -0,0 +1 @@ +{"code_snippets":[{"id":"814810e1e2a875e8055c149185d2ca88","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java","line_range":"24-72","gmt_create":"2026-01-29T21:49:21.8928359+08:00","gmt_modified":"2026-01-29T21:49:21.8928359+08:00"},{"id":"f9ae254d631b05eefcc5414aa2baa65a","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java","line_range":"42-283","gmt_create":"2026-01-29T21:49:21.8928359+08:00","gmt_modified":"2026-01-29T21:49:21.8928359+08:00"},{"id":"19cf3abc64d0f832b3fc2241ad064717","path":"datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java","line_range":"28-45","gmt_create":"2026-01-29T21:49:21.8933405+08:00","gmt_modified":"2026-01-29T21:49:21.8933405+08:00"},{"id":"2d56d5b0b4a327e2f8267aeac2765f1f","path":"datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java","line_range":"28-54","gmt_create":"2026-01-29T21:49:21.8938381+08:00","gmt_modified":"2026-01-29T21:49:21.8938381+08:00"},{"id":"8b827b3d0cb5a8c0d43c0b422bcba4cd","path":"datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java","line_range":"28-59","gmt_create":"2026-01-29T21:49:21.8938381+08:00","gmt_modified":"2026-01-29T21:49:21.8938381+08:00"},{"id":"80a2d925ae81604e425cb61eee2a5949","path":"datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java","line_range":"28-75","gmt_create":"2026-01-29T21:49:21.8943374+08:00","gmt_modified":"2026-01-29T21:49:21.8943374+08:00"},{"id":"b9f27ead9db0af93d7434b5026712f07","path":"datavines-connector/datavines-connector-plugins/datavines-connector-clickhouse/src/main/java/io/datavines/connector/plugin/ClickHouseConnector.java","line_range":"27-46","gmt_create":"2026-01-29T21:49:21.8948346+08:00","gmt_modified":"2026-01-29T21:49:21.8948346+08:00"},{"id":"ad3a1bd5e995be8af6e9c70958ffbbae","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java","line_range":"40-251","gmt_create":"2026-01-29T21:49:21.8953351+08:00","gmt_modified":"2026-01-29T21:49:21.8953351+08:00"},{"id":"4dab60fa9d135a3a3f8767779fe7fa6f","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java","line_range":"33-150","gmt_create":"2026-01-29T21:49:21.8963337+08:00","gmt_modified":"2026-01-29T21:49:21.8963337+08:00"},{"id":"f6753f13f7cf9daaccb1defb4eb22781","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java","line_range":"33-75","gmt_create":"2026-01-29T21:49:21.8968336+08:00","gmt_modified":"2026-01-29T21:49:21.8968336+08:00"},{"id":"561dea64cc76d5df6c5352fb74fc7569","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDialect.java","line_range":"19-25","gmt_create":"2026-01-29T21:49:21.8973334+08:00","gmt_modified":"2026-01-29T21:49:21.8973334+08:00"},{"id":"f0ca1df1a5911701ee393be59add314d","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java","line_range":"24-46","gmt_create":"2026-01-29T21:49:21.8988859+08:00","gmt_modified":"2026-01-29T21:49:21.8988859+08:00"},{"id":"5080e00c0ba0973d12721f8a9139d20d","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java","line_range":"34-116","gmt_create":"2026-01-29T21:49:21.8993746+08:00","gmt_modified":"2026-01-29T21:49:21.8993746+08:00"},{"id":"805c6ce717dfa901e13c631bf6c9b5bc","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisExecutor.java","line_range":"24-35","gmt_create":"2026-01-29T21:49:21.8993746+08:00","gmt_modified":"2026-01-29T21:49:21.8993746+08:00"},{"id":"8046f83719b4709b42935e4b518c3923","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java","line_range":"30-47","gmt_create":"2026-01-29T21:49:21.9003704+08:00","gmt_modified":"2026-01-29T21:49:21.9003704+08:00"},{"id":"2aba75aec896281e18c1821cafc696d9","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java","line_range":"32-88","gmt_create":"2026-01-29T21:49:21.9003704+08:00","gmt_modified":"2026-01-29T21:49:21.9003704+08:00"},{"id":"381316af739d43973d0f5a5ad0d5aaf3","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java","line_range":"72-85","gmt_create":"2026-01-29T21:49:21.9038355+08:00","gmt_modified":"2026-01-29T21:49:21.9038355+08:00"},{"id":"9115e5d018e2a599c9783f2151a77f9d","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java","line_range":"206-249","gmt_create":"2026-01-29T21:49:21.9043342+08:00","gmt_modified":"2026-01-29T21:49:21.9043342+08:00"},{"id":"ef0659592beb83e1abc532bb877b164a","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java","line_range":"25-59","gmt_create":"2026-01-29T21:49:21.9053326+08:00","gmt_modified":"2026-01-29T21:49:21.9053326+08:00"},{"id":"38b45138543833f148982d52908c6f91","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java","line_range":"23-62","gmt_create":"2026-01-29T21:49:21.9053326+08:00","gmt_modified":"2026-01-29T21:49:21.9053326+08:00"},{"id":"05c52b772dc3dcb9b030a651d6aa946c","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java","line_range":"25-51","gmt_create":"2026-01-29T21:49:21.9059798+08:00","gmt_modified":"2026-01-29T21:49:21.9059798+08:00"},{"id":"89cc9187af0b648ba39e93d5725636d4","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java","line_range":"21-48","gmt_create":"2026-01-29T21:49:21.9063322+08:00","gmt_modified":"2026-01-29T21:49:21.9063322+08:00"},{"id":"0a09dfdafd728bc656da6e0f2c7e8fb0","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java","line_range":"19-24","gmt_create":"2026-01-29T21:49:21.9063322+08:00","gmt_modified":"2026-01-29T21:49:21.9063322+08:00"},{"id":"d59fb437d7c5b71dd7534adb6d21109f","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java","line_range":"36-150","gmt_create":"2026-01-29T21:49:21.9068321+08:00","gmt_modified":"2026-01-29T21:49:21.9068321+08:00"},{"id":"fb17021b483fcb4a4bf766b794642ad3","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java","line_range":"35-42","gmt_create":"2026-01-29T21:49:21.9078384+08:00","gmt_modified":"2026-01-29T21:49:21.9078384+08:00"},{"id":"1e84740a4cc545f9064a8bbfc9510252","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java","line_range":"28-49","gmt_create":"2026-01-29T21:49:21.9083325+08:00","gmt_modified":"2026-01-29T21:49:21.9083325+08:00"},{"id":"991962c9ca7bad79a3806e4eb014a15c","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java","line_range":"38-60","gmt_create":"2026-01-29T21:49:21.9085024+08:00","gmt_modified":"2026-01-29T21:49:21.9085024+08:00"},{"id":"9bf43004076c4f684bcd41403a176163","path":"datavines-ui\\src\\http\\index.ts","line_range":"24-50","gmt_create":"2026-02-05T02:04:29.1006489+08:00","gmt_modified":"2026-02-05T02:04:29.1006489+08:00"},{"id":"6096882f6c5eb65bf0122ffe3c9b1f3b","path":"datavines-ui\\Editor\\http\\response.interceptor.ts","line_range":"1-106","gmt_create":"2026-02-05T02:04:29.10126+08:00","gmt_modified":"2026-02-05T02:04:29.10126+08:00"},{"id":"2e41a2957effa882695d7e13ae5734f4","path":"datavines-ui\\src\\http\\index.ts","line_range":"9-22","gmt_create":"2026-02-05T02:04:29.10126+08:00","gmt_modified":"2026-02-05T02:04:29.10126+08:00"},{"id":"112b9005cde5a20dde537db782954868","path":"datavines-ui\\src\\http\\index.ts","line_range":"39-47","gmt_create":"2026-02-05T02:04:29.1017731+08:00","gmt_modified":"2026-02-05T02:04:29.1017731+08:00"},{"id":"1e2d302b8b8dd34e92da513b1bfca148","path":"datavines-ui\\src\\utils\\constants.ts","line_range":"6","gmt_create":"2026-02-05T02:04:29.1018811+08:00","gmt_modified":"2026-02-05T02:04:29.1018811+08:00"},{"id":"76f1f03d035ebabc5917a536653dc49a","path":"datavines-ui\\src\\http\\index.ts","line_range":"9-48","gmt_create":"2026-02-05T02:04:29.1018811+08:00","gmt_modified":"2026-02-05T02:04:29.1018811+08:00"},{"id":"0c70ad0717f07f161005eb61b3171a54","path":"datavines-ui\\src\\store\\index.ts","line_range":"12-15","gmt_create":"2026-02-05T02:04:29.1018811+08:00","gmt_modified":"2026-02-05T02:04:29.1018811+08:00"},{"id":"3b9180c665d9df925335a38c94238628","path":"datavines-ui\\src\\store\\rootReducer.ts","line_range":"6-11","gmt_create":"2026-02-05T02:04:29.1018811+08:00","gmt_modified":"2026-02-05T02:04:29.1018811+08:00"},{"id":"9f82b508634e3489911c78cf693800c6","path":"datavines-ui\\src\\store\\index.ts","line_range":"20-23","gmt_create":"2026-02-05T02:04:29.1024039+08:00","gmt_modified":"2026-02-05T02:04:29.1024039+08:00"},{"id":"2f23f438ddbcf34e11b08b9d8b438732","path":"datavines-ui\\src\\store\\commonReducer\\index.ts","line_range":"41-53","gmt_create":"2026-02-05T02:04:29.102477+08:00","gmt_modified":"2026-02-05T02:04:29.102477+08:00"},{"id":"b0833565150b237c231cb07da13c93e9","path":"datavines-ui\\src\\store\\index.ts","line_range":"1-26","gmt_create":"2026-02-05T02:04:29.102477+08:00","gmt_modified":"2026-02-05T02:04:29.102477+08:00"},{"id":"faea7c20546d37fa1c0d4d67b5da2cd4","path":"datavines-ui\\src\\store\\rootReducer.ts","line_range":"1-26","gmt_create":"2026-02-05T02:04:29.102477+08:00","gmt_modified":"2026-02-05T02:04:29.102477+08:00"},{"id":"cf969e66d861a099a266361fde36337b","path":"datavines-ui\\src\\store\\commonReducer\\index.ts","line_range":"1-73","gmt_create":"2026-02-05T02:04:29.1029854+08:00","gmt_modified":"2026-02-05T02:04:29.1029854+08:00"},{"id":"1853a9bfcf63e242ea1c0f605459182a","path":"datavines-ui\\src\\type\\User.ts","line_range":"1-8","gmt_create":"2026-02-05T02:04:29.1029854+08:00","gmt_modified":"2026-02-05T02:04:29.1029854+08:00"},{"id":"ee09aa347bf39e20805310c59a20bf59","path":"datavines-ui\\src\\type\\Jobs.ts","line_range":"1-10","gmt_create":"2026-02-05T02:04:29.1029854+08:00","gmt_modified":"2026-02-05T02:04:29.1029854+08:00"},{"id":"d68efb4c554e2c0cad5636c6461b5ea7","path":"datavines-ui\\src\\type\\dataSource.ts","line_range":"36-50","gmt_create":"2026-02-05T02:04:29.1040611+08:00","gmt_modified":"2026-02-05T02:04:29.1040611+08:00"},{"id":"8206193c6be9e9d0c6d7f4abeef8370e","path":"datavines-ui\\src\\type\\dataSource.ts","line_range":"1-50","gmt_create":"2026-02-05T02:04:29.104572+08:00","gmt_modified":"2026-02-05T02:04:29.104572+08:00"},{"id":"d105954b07e16d85a5326375dd11c3b6","path":"datavines-ui\\src\\component\\SwitchLanguage\\index.tsx","line_range":"1-38","gmt_create":"2026-02-05T02:04:29.104649+08:00","gmt_modified":"2026-02-05T02:04:29.104649+08:00"},{"id":"79c2e4fc4483c00a3c78c4239cd593f5","path":"datavines-ui\\src\\locale\\index.tsx","line_range":"32-55","gmt_create":"2026-02-05T02:04:29.104649+08:00","gmt_modified":"2026-02-05T02:04:29.104649+08:00"},{"id":"82ab25cb7be7255422c3e7de450cbbe7","path":"datavines-ui\\Editor\\http\\response.interceptor.ts","line_range":"4-10","gmt_create":"2026-02-05T02:04:29.104649+08:00","gmt_modified":"2026-02-05T02:04:29.104649+08:00"},{"id":"89e0967c031c588772da4cbf53ad94ef","path":"datavines-ui\\Editor\\http\\response.interceptor.ts","line_range":"42-45","gmt_create":"2026-02-05T02:04:29.105156+08:00","gmt_modified":"2026-02-05T02:04:29.105156+08:00"},{"id":"3fd956cb1ffa8527dcd23185e5ef12b0","path":"datavines-ui\\Editor\\locale\\zh_CN.ts","line_range":"1-85","gmt_create":"2026-02-05T02:04:29.105156+08:00","gmt_modified":"2026-02-05T02:04:29.105156+08:00"},{"id":"b01f4b6de7cd7b3da94c84fa78ac8f9e","path":"datavines-ui\\Editor\\locale\\en_US.ts","line_range":"1-85","gmt_create":"2026-02-05T02:04:29.1057007+08:00","gmt_modified":"2026-02-05T02:04:29.1057007+08:00"},{"id":"e93fc8c82647c8dbf3029027e58fcc29","path":"datavines-ui\\src\\locale\\index.tsx","line_range":"1-56","gmt_create":"2026-02-05T02:04:29.1057007+08:00","gmt_modified":"2026-02-05T02:04:29.1057007+08:00"},{"id":"41de8a8a30bc9e0da8b7f1b51a2b1f7e","path":"datavines-ui\\src\\http\\index.ts","line_range":"39-43","gmt_create":"2026-02-05T02:04:29.106242+08:00","gmt_modified":"2026-02-05T02:04:29.106242+08:00"},{"id":"d57fd58ee96f8528eada711d6589be84","path":"datavines-ui\\src\\store\\index.ts","line_range":"7","gmt_create":"2026-02-05T02:04:29.106242+08:00","gmt_modified":"2026-02-05T02:04:29.106242+08:00"},{"id":"72804749f64d9a0e44f88500848de061","path":"datavines-ui\\Editor\\http\\response.interceptor.ts","line_range":"66-105","gmt_create":"2026-02-05T02:04:29.106242+08:00","gmt_modified":"2026-02-05T02:04:29.106242+08:00"},{"id":"fead59530b734a2d6d10d3a8bdf0a471","path":"datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java","line_range":"44-167","gmt_create":"2026-02-05T02:06:49.3181821+08:00","gmt_modified":"2026-02-05T02:06:49.3181821+08:00"},{"id":"2cbc150b094a14be555fe5982c5234ea","path":"datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java","line_range":"56-167","gmt_create":"2026-02-05T02:06:49.3181821+08:00","gmt_modified":"2026-02-05T02:06:49.3181821+08:00"},{"id":"b20b55d193d5fc59c3439d3ca4b2430d","path":"datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java","line_range":"32-51","gmt_create":"2026-02-05T02:06:49.3181821+08:00","gmt_modified":"2026-02-05T02:06:49.3181821+08:00"},{"id":"6bd7929e5a5668930216c58bf96dd67b","path":"datavines-connector/connector-plugins/connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java","line_range":"36-72","gmt_create":"2026-02-05T02:06:49.3181821+08:00","gmt_modified":"2026-02-05T02:06:49.3181821+08:00"},{"id":"096cd1fb8b55d7adbbf50d3960d8446b","path":"datavines-connector/connector-plugins/connector-oracle/src/main/java/io/datavines/connector/plugin/OracleParameterConverter.java","line_range":"25-44","gmt_create":"2026-02-05T02:06:49.3189553+08:00","gmt_modified":"2026-02-05T02:06:49.3189553+08:00"},{"id":"85f0fa99dcc801a5e262826c1de187aa","path":"datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java","line_range":"26-39","gmt_create":"2026-02-05T02:06:49.3191412+08:00","gmt_modified":"2026-02-05T02:06:49.3191412+08:00"},{"id":"cf33c5c40617d467214ee6588937e66a","path":"datavines-server/src/main/java/io/datavines/server/api/dto/vo/DataSourceVO.java","line_range":"25-42","gmt_create":"2026-02-05T02:06:49.3193736+08:00","gmt_modified":"2026-02-05T02:06:49.3193736+08:00"},{"id":"1fb4075d646177f68ff77351f534d081","path":"datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java","line_range":"59-86","gmt_create":"2026-02-05T02:06:49.3193736+08:00","gmt_modified":"2026-02-05T02:06:49.3193736+08:00"},{"id":"5f8e12524eb6a169d5684eb901fc47db","path":"datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java","line_range":"22-25","gmt_create":"2026-02-05T02:06:49.3193736+08:00","gmt_modified":"2026-02-05T02:06:49.3193736+08:00"},{"id":"7656d5e22134969f34088283ee21a277","path":"datavines-common/src/main/java/io/datavines/common/param/ConnectorRequestParam.java","line_range":"22-27","gmt_create":"2026-02-05T02:06:49.3196797+08:00","gmt_modified":"2026-02-05T02:06:49.3196797+08:00"},{"id":"79af665211fd45dd3fc2b76e80dbe54f","path":"datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java","line_range":"22-52","gmt_create":"2026-02-05T02:06:49.3196797+08:00","gmt_modified":"2026-02-05T02:06:49.3196797+08:00"},{"id":"7c2bf2c7c0f153865c5f4168f4eca72e","path":"datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java","line_range":"29-128","gmt_create":"2026-02-05T02:06:49.319873+08:00","gmt_modified":"2026-02-05T02:06:49.319873+08:00"},{"id":"1f8d4de5fb17a98f10ff241f0609a143","path":"datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java","line_range":"75-78","gmt_create":"2026-02-05T02:06:49.319873+08:00","gmt_modified":"2026-02-05T02:06:49.319873+08:00"},{"id":"68aeb7cbcb88b7f348067a268be9c509","path":"datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java","line_range":"26-64","gmt_create":"2026-02-05T02:06:49.319873+08:00","gmt_modified":"2026-02-05T02:06:49.319873+08:00"},{"id":"15d8c34316cb2c4c7b36ed301bb3a0c8","path":"datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java","line_range":"150-197","gmt_create":"2026-02-05T02:06:49.319873+08:00","gmt_modified":"2026-02-05T02:06:49.319873+08:00"},{"id":"3d8e6a2bb3008d205ea5fe594e05c115","path":"datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java","line_range":"113-116","gmt_create":"2026-02-05T02:06:49.3203733+08:00","gmt_modified":"2026-02-05T02:06:49.3203733+08:00"},{"id":"e3f35a91be57cc656f6fa5e2323cf88a","path":"datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java","line_range":"184-189","gmt_create":"2026-02-05T02:06:49.3205005+08:00","gmt_modified":"2026-02-05T02:06:49.3205005+08:00"}],"knowledge_relations":[{"id":1274,"source_id":"b0df0e39-2431-4b39-b088-89a48f0ecb28","target_id":"ac2110cd-0960-4312-addd-3ab1ecbbd2f8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0df0e39-2431-4b39-b088-89a48f0ecb28 -\u003e ac2110cd-0960-4312-addd-3ab1ecbbd2f8","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1275,"source_id":"b0df0e39-2431-4b39-b088-89a48f0ecb28","target_id":"fbafebaa-f8fe-4bc6-81b2-d1213e01488d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0df0e39-2431-4b39-b088-89a48f0ecb28 -\u003e fbafebaa-f8fe-4bc6-81b2-d1213e01488d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1276,"source_id":"b0df0e39-2431-4b39-b088-89a48f0ecb28","target_id":"804673b7-443f-4e85-8b92-5e308209d0f5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0df0e39-2431-4b39-b088-89a48f0ecb28 -\u003e 804673b7-443f-4e85-8b92-5e308209d0f5","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1277,"source_id":"b0df0e39-2431-4b39-b088-89a48f0ecb28","target_id":"74831571-fcde-4baf-9bc1-e6e4f3a25a3f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0df0e39-2431-4b39-b088-89a48f0ecb28 -\u003e 74831571-fcde-4baf-9bc1-e6e4f3a25a3f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1278,"source_id":"b0df0e39-2431-4b39-b088-89a48f0ecb28","target_id":"a15d849e-26b1-4748-b931-e66cd3927445","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b0df0e39-2431-4b39-b088-89a48f0ecb28 -\u003e a15d849e-26b1-4748-b931-e66cd3927445","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1279,"source_id":"d50d63e5-3a8f-4a16-8d03-e59d23082f71","target_id":"0eefe69b-2f6c-475e-898c-1e0cc92580fc","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d50d63e5-3a8f-4a16-8d03-e59d23082f71 -\u003e 0eefe69b-2f6c-475e-898c-1e0cc92580fc","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1280,"source_id":"d50d63e5-3a8f-4a16-8d03-e59d23082f71","target_id":"b12680e1-7a47-4deb-9e20-da52e326b2a9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d50d63e5-3a8f-4a16-8d03-e59d23082f71 -\u003e b12680e1-7a47-4deb-9e20-da52e326b2a9","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1282,"source_id":"d50d63e5-3a8f-4a16-8d03-e59d23082f71","target_id":"a6e195e7-dd42-43aa-abc7-67405e121060","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d50d63e5-3a8f-4a16-8d03-e59d23082f71 -\u003e a6e195e7-dd42-43aa-abc7-67405e121060","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1283,"source_id":"d50d63e5-3a8f-4a16-8d03-e59d23082f71","target_id":"c3d8eae5-592e-4859-bdc3-81f5ebeda695","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d50d63e5-3a8f-4a16-8d03-e59d23082f71 -\u003e c3d8eae5-592e-4859-bdc3-81f5ebeda695","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1284,"source_id":"d50d63e5-3a8f-4a16-8d03-e59d23082f71","target_id":"d2c9ad66-a827-4029-b221-942b9f1ffff2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d50d63e5-3a8f-4a16-8d03-e59d23082f71 -\u003e d2c9ad66-a827-4029-b221-942b9f1ffff2","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1285,"source_id":"d50d63e5-3a8f-4a16-8d03-e59d23082f71","target_id":"4568681a-4970-4d2f-86cc-330effb87a9d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d50d63e5-3a8f-4a16-8d03-e59d23082f71 -\u003e 4568681a-4970-4d2f-86cc-330effb87a9d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1286,"source_id":"6bf414f3-9d02-4d7a-aea2-53c73bca4e06","target_id":"cbb42b6e-b7b1-4826-b4d2-d027e2f67605","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6bf414f3-9d02-4d7a-aea2-53c73bca4e06 -\u003e cbb42b6e-b7b1-4826-b4d2-d027e2f67605","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1287,"source_id":"6bf414f3-9d02-4d7a-aea2-53c73bca4e06","target_id":"306a8ebd-014f-4c6a-974a-7f77a567169a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6bf414f3-9d02-4d7a-aea2-53c73bca4e06 -\u003e 306a8ebd-014f-4c6a-974a-7f77a567169a","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1288,"source_id":"6bf414f3-9d02-4d7a-aea2-53c73bca4e06","target_id":"003fa99c-2fe9-4ccf-af4d-40cd84634a20","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6bf414f3-9d02-4d7a-aea2-53c73bca4e06 -\u003e 003fa99c-2fe9-4ccf-af4d-40cd84634a20","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1289,"source_id":"b3dec9f6-4de5-4825-b008-9dad708eddee","target_id":"df2be99f-e3e1-4868-9a5e-299481db7fda","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b3dec9f6-4de5-4825-b008-9dad708eddee -\u003e df2be99f-e3e1-4868-9a5e-299481db7fda","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1290,"source_id":"b3dec9f6-4de5-4825-b008-9dad708eddee","target_id":"e4b9927b-7ccf-49a0-aa45-e971ba14af22","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b3dec9f6-4de5-4825-b008-9dad708eddee -\u003e e4b9927b-7ccf-49a0-aa45-e971ba14af22","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1291,"source_id":"b3dec9f6-4de5-4825-b008-9dad708eddee","target_id":"22f30c31-0e11-42d3-bab8-e31b8ff300e9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b3dec9f6-4de5-4825-b008-9dad708eddee -\u003e 22f30c31-0e11-42d3-bab8-e31b8ff300e9","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1292,"source_id":"b3dec9f6-4de5-4825-b008-9dad708eddee","target_id":"23f64f7d-e748-4db2-9a32-e58b874a437a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b3dec9f6-4de5-4825-b008-9dad708eddee -\u003e 23f64f7d-e748-4db2-9a32-e58b874a437a","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1293,"source_id":"b3dec9f6-4de5-4825-b008-9dad708eddee","target_id":"f75ee18b-fc66-4a0f-9ee7-866f530271cd","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b3dec9f6-4de5-4825-b008-9dad708eddee -\u003e f75ee18b-fc66-4a0f-9ee7-866f530271cd","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1295,"source_id":"a8bc817f-96f5-400b-a9c9-8cd17a45753e","target_id":"387347fe-4237-48a8-9de1-8c8b419d5ef6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a8bc817f-96f5-400b-a9c9-8cd17a45753e -\u003e 387347fe-4237-48a8-9de1-8c8b419d5ef6","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1296,"source_id":"a8bc817f-96f5-400b-a9c9-8cd17a45753e","target_id":"37db11bb-2ce0-40c9-af65-2c5a1ee2bdde","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a8bc817f-96f5-400b-a9c9-8cd17a45753e -\u003e 37db11bb-2ce0-40c9-af65-2c5a1ee2bdde","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1297,"source_id":"a8bc817f-96f5-400b-a9c9-8cd17a45753e","target_id":"a3e22b74-44ee-4f88-b6d0-d1bf700087aa","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a8bc817f-96f5-400b-a9c9-8cd17a45753e -\u003e a3e22b74-44ee-4f88-b6d0-d1bf700087aa","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1298,"source_id":"a8bc817f-96f5-400b-a9c9-8cd17a45753e","target_id":"9289d9a1-d1a9-451c-84e8-644917a63856","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a8bc817f-96f5-400b-a9c9-8cd17a45753e -\u003e 9289d9a1-d1a9-451c-84e8-644917a63856","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1299,"source_id":"13baf602-8637-4c51-92f1-25bbcbb79482","target_id":"3472a28e-5ec7-467d-a9a1-6b9ee9048f25","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 13baf602-8637-4c51-92f1-25bbcbb79482 -\u003e 3472a28e-5ec7-467d-a9a1-6b9ee9048f25","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1300,"source_id":"13baf602-8637-4c51-92f1-25bbcbb79482","target_id":"303be0ec-64a2-41d5-9125-7dd46f7fa54a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 13baf602-8637-4c51-92f1-25bbcbb79482 -\u003e 303be0ec-64a2-41d5-9125-7dd46f7fa54a","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1301,"source_id":"13baf602-8637-4c51-92f1-25bbcbb79482","target_id":"ce19faf8-ef6d-4718-82ce-772d2a15628a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 13baf602-8637-4c51-92f1-25bbcbb79482 -\u003e ce19faf8-ef6d-4718-82ce-772d2a15628a","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1302,"source_id":"13baf602-8637-4c51-92f1-25bbcbb79482","target_id":"fc141673-0101-41e5-8fbd-185a232358e8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 13baf602-8637-4c51-92f1-25bbcbb79482 -\u003e fc141673-0101-41e5-8fbd-185a232358e8","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1304,"source_id":"13baf602-8637-4c51-92f1-25bbcbb79482","target_id":"0617f6de-bc78-4987-b57a-d81e6802ff10","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 13baf602-8637-4c51-92f1-25bbcbb79482 -\u003e 0617f6de-bc78-4987-b57a-d81e6802ff10","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1305,"source_id":"d79ed45b-d152-4c64-a634-4f57dbce5c7e","target_id":"3c8a2b52-48dc-4d07-ad73-21ccb25d802b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d79ed45b-d152-4c64-a634-4f57dbce5c7e -\u003e 3c8a2b52-48dc-4d07-ad73-21ccb25d802b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1306,"source_id":"d79ed45b-d152-4c64-a634-4f57dbce5c7e","target_id":"bdb0ca87-0492-4589-9586-aac561342153","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d79ed45b-d152-4c64-a634-4f57dbce5c7e -\u003e bdb0ca87-0492-4589-9586-aac561342153","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1307,"source_id":"d79ed45b-d152-4c64-a634-4f57dbce5c7e","target_id":"ed40592f-2d32-4954-97c2-25884d935486","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d79ed45b-d152-4c64-a634-4f57dbce5c7e -\u003e ed40592f-2d32-4954-97c2-25884d935486","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1308,"source_id":"d79ed45b-d152-4c64-a634-4f57dbce5c7e","target_id":"e54ee939-b8ee-4f97-b731-2e56428b4f5d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d79ed45b-d152-4c64-a634-4f57dbce5c7e -\u003e e54ee939-b8ee-4f97-b731-2e56428b4f5d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1309,"source_id":"cbb42b6e-b7b1-4826-b4d2-d027e2f67605","target_id":"eeeebcfe-e030-4d58-b0ad-7b86db5b5172","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cbb42b6e-b7b1-4826-b4d2-d027e2f67605 -\u003e eeeebcfe-e030-4d58-b0ad-7b86db5b5172","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1310,"source_id":"cbb42b6e-b7b1-4826-b4d2-d027e2f67605","target_id":"9d420715-99bb-45a0-9e7f-4b662cb4ffbf","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cbb42b6e-b7b1-4826-b4d2-d027e2f67605 -\u003e 9d420715-99bb-45a0-9e7f-4b662cb4ffbf","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1311,"source_id":"cbb42b6e-b7b1-4826-b4d2-d027e2f67605","target_id":"c646e112-10e4-4618-b290-d1bd1129c913","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cbb42b6e-b7b1-4826-b4d2-d027e2f67605 -\u003e c646e112-10e4-4618-b290-d1bd1129c913","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1312,"source_id":"ac2110cd-0960-4312-addd-3ab1ecbbd2f8","target_id":"9b2bd429-f32e-4cb5-be78-92dc13b4fa70","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ac2110cd-0960-4312-addd-3ab1ecbbd2f8 -\u003e 9b2bd429-f32e-4cb5-be78-92dc13b4fa70","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1313,"source_id":"ac2110cd-0960-4312-addd-3ab1ecbbd2f8","target_id":"e4cb9c4e-b0e0-4a2e-96d7-288ea1a7ba86","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ac2110cd-0960-4312-addd-3ab1ecbbd2f8 -\u003e e4cb9c4e-b0e0-4a2e-96d7-288ea1a7ba86","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1314,"source_id":"ac2110cd-0960-4312-addd-3ab1ecbbd2f8","target_id":"1dbe65d5-1994-445e-aeed-7ca8a425006c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ac2110cd-0960-4312-addd-3ab1ecbbd2f8 -\u003e 1dbe65d5-1994-445e-aeed-7ca8a425006c","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1315,"source_id":"0eefe69b-2f6c-475e-898c-1e0cc92580fc","target_id":"9004726b-863c-4b95-8945-0588eecef92b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0eefe69b-2f6c-475e-898c-1e0cc92580fc -\u003e 9004726b-863c-4b95-8945-0588eecef92b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1316,"source_id":"0eefe69b-2f6c-475e-898c-1e0cc92580fc","target_id":"d6546d25-2b85-4290-adde-19b5018a30e3","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0eefe69b-2f6c-475e-898c-1e0cc92580fc -\u003e d6546d25-2b85-4290-adde-19b5018a30e3","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1317,"source_id":"0eefe69b-2f6c-475e-898c-1e0cc92580fc","target_id":"b25549e7-1a1b-4262-b87b-68f496c361e5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0eefe69b-2f6c-475e-898c-1e0cc92580fc -\u003e b25549e7-1a1b-4262-b87b-68f496c361e5","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1318,"source_id":"0eefe69b-2f6c-475e-898c-1e0cc92580fc","target_id":"094cefaf-bbca-448f-a303-c381ff621065","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0eefe69b-2f6c-475e-898c-1e0cc92580fc -\u003e 094cefaf-bbca-448f-a303-c381ff621065","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1319,"source_id":"0eefe69b-2f6c-475e-898c-1e0cc92580fc","target_id":"c7c1b23e-9e57-4fe0-b507-b33dbce122c2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0eefe69b-2f6c-475e-898c-1e0cc92580fc -\u003e c7c1b23e-9e57-4fe0-b507-b33dbce122c2","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1320,"source_id":"0eefe69b-2f6c-475e-898c-1e0cc92580fc","target_id":"e6b9d590-5e80-4e8a-99e5-5cbbed8e6c33","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0eefe69b-2f6c-475e-898c-1e0cc92580fc -\u003e e6b9d590-5e80-4e8a-99e5-5cbbed8e6c33","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1321,"source_id":"b43aa946-6bd8-4b94-a366-7b99f7566ca5","target_id":"285a47d3-4238-4eb3-af06-601a74713b41","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b43aa946-6bd8-4b94-a366-7b99f7566ca5 -\u003e 285a47d3-4238-4eb3-af06-601a74713b41","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1322,"source_id":"b43aa946-6bd8-4b94-a366-7b99f7566ca5","target_id":"063cbaf7-e00b-4a07-a62d-df3b797bc32f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b43aa946-6bd8-4b94-a366-7b99f7566ca5 -\u003e 063cbaf7-e00b-4a07-a62d-df3b797bc32f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1323,"source_id":"b43aa946-6bd8-4b94-a366-7b99f7566ca5","target_id":"eb68e142-cbc4-4cee-8e70-1895d610c66c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b43aa946-6bd8-4b94-a366-7b99f7566ca5 -\u003e eb68e142-cbc4-4cee-8e70-1895d610c66c","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1324,"source_id":"b43aa946-6bd8-4b94-a366-7b99f7566ca5","target_id":"ba65cb6b-cfec-491c-98ae-2a74f573fcd2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b43aa946-6bd8-4b94-a366-7b99f7566ca5 -\u003e ba65cb6b-cfec-491c-98ae-2a74f573fcd2","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1325,"source_id":"b43aa946-6bd8-4b94-a366-7b99f7566ca5","target_id":"44d4499c-ef2d-4ff0-8606-56397e9e1315","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b43aa946-6bd8-4b94-a366-7b99f7566ca5 -\u003e 44d4499c-ef2d-4ff0-8606-56397e9e1315","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1326,"source_id":"fbafebaa-f8fe-4bc6-81b2-d1213e01488d","target_id":"952b9290-106c-41d2-b6cc-8b629ae6eac4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: fbafebaa-f8fe-4bc6-81b2-d1213e01488d -\u003e 952b9290-106c-41d2-b6cc-8b629ae6eac4","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1327,"source_id":"fbafebaa-f8fe-4bc6-81b2-d1213e01488d","target_id":"0c774ddd-d820-4982-84c2-e396ababa803","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: fbafebaa-f8fe-4bc6-81b2-d1213e01488d -\u003e 0c774ddd-d820-4982-84c2-e396ababa803","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1328,"source_id":"fbafebaa-f8fe-4bc6-81b2-d1213e01488d","target_id":"f6c98e31-e00f-4acf-b95e-0e98fface5c5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: fbafebaa-f8fe-4bc6-81b2-d1213e01488d -\u003e f6c98e31-e00f-4acf-b95e-0e98fface5c5","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1329,"source_id":"fbafebaa-f8fe-4bc6-81b2-d1213e01488d","target_id":"d64dafa2-9b28-49c1-b140-df804355c0cb","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: fbafebaa-f8fe-4bc6-81b2-d1213e01488d -\u003e d64dafa2-9b28-49c1-b140-df804355c0cb","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1330,"source_id":"3472a28e-5ec7-467d-a9a1-6b9ee9048f25","target_id":"2eb18165-85cd-4ec3-8966-184c430fa3a7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3472a28e-5ec7-467d-a9a1-6b9ee9048f25 -\u003e 2eb18165-85cd-4ec3-8966-184c430fa3a7","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1331,"source_id":"3472a28e-5ec7-467d-a9a1-6b9ee9048f25","target_id":"75988d09-2105-4ebf-8f4d-8d84f195685c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3472a28e-5ec7-467d-a9a1-6b9ee9048f25 -\u003e 75988d09-2105-4ebf-8f4d-8d84f195685c","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1332,"source_id":"3472a28e-5ec7-467d-a9a1-6b9ee9048f25","target_id":"10d8c2d5-b907-449d-90c7-b8136ef223c0","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3472a28e-5ec7-467d-a9a1-6b9ee9048f25 -\u003e 10d8c2d5-b907-449d-90c7-b8136ef223c0","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1333,"source_id":"3472a28e-5ec7-467d-a9a1-6b9ee9048f25","target_id":"a185d6d3-65d3-42ce-9fed-34d262f82c59","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3472a28e-5ec7-467d-a9a1-6b9ee9048f25 -\u003e a185d6d3-65d3-42ce-9fed-34d262f82c59","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1334,"source_id":"306a8ebd-014f-4c6a-974a-7f77a567169a","target_id":"a5e589d4-d359-4c6a-937d-772308efaa81","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 306a8ebd-014f-4c6a-974a-7f77a567169a -\u003e a5e589d4-d359-4c6a-937d-772308efaa81","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1335,"source_id":"306a8ebd-014f-4c6a-974a-7f77a567169a","target_id":"76361208-bf89-4b44-9748-f8143863d49c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 306a8ebd-014f-4c6a-974a-7f77a567169a -\u003e 76361208-bf89-4b44-9748-f8143863d49c","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1336,"source_id":"306a8ebd-014f-4c6a-974a-7f77a567169a","target_id":"40967690-1b17-417e-a87f-705788d6a788","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 306a8ebd-014f-4c6a-974a-7f77a567169a -\u003e 40967690-1b17-417e-a87f-705788d6a788","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1337,"source_id":"306a8ebd-014f-4c6a-974a-7f77a567169a","target_id":"cb8ab5c0-64d4-4f64-b62d-0f28cd29f12e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 306a8ebd-014f-4c6a-974a-7f77a567169a -\u003e cb8ab5c0-64d4-4f64-b62d-0f28cd29f12e","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1338,"source_id":"b12680e1-7a47-4deb-9e20-da52e326b2a9","target_id":"549d317b-d01d-4daf-b9f0-885468969f8b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b12680e1-7a47-4deb-9e20-da52e326b2a9 -\u003e 549d317b-d01d-4daf-b9f0-885468969f8b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1339,"source_id":"b12680e1-7a47-4deb-9e20-da52e326b2a9","target_id":"23c19f37-93ba-429a-b47b-2d2bdc9354dc","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b12680e1-7a47-4deb-9e20-da52e326b2a9 -\u003e 23c19f37-93ba-429a-b47b-2d2bdc9354dc","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1340,"source_id":"b12680e1-7a47-4deb-9e20-da52e326b2a9","target_id":"3f71db44-01be-4380-975c-b6ccd8906956","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b12680e1-7a47-4deb-9e20-da52e326b2a9 -\u003e 3f71db44-01be-4380-975c-b6ccd8906956","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1341,"source_id":"b12680e1-7a47-4deb-9e20-da52e326b2a9","target_id":"9d43b1ad-ce04-4422-b736-cc8edf592394","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b12680e1-7a47-4deb-9e20-da52e326b2a9 -\u003e 9d43b1ad-ce04-4422-b736-cc8edf592394","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1342,"source_id":"b12680e1-7a47-4deb-9e20-da52e326b2a9","target_id":"37db4c74-0075-4d61-a617-961a2bb2b02c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b12680e1-7a47-4deb-9e20-da52e326b2a9 -\u003e 37db4c74-0075-4d61-a617-961a2bb2b02c","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1343,"source_id":"387347fe-4237-48a8-9de1-8c8b419d5ef6","target_id":"b4875857-d9cc-4356-a846-109504feceae","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 387347fe-4237-48a8-9de1-8c8b419d5ef6 -\u003e b4875857-d9cc-4356-a846-109504feceae","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1344,"source_id":"387347fe-4237-48a8-9de1-8c8b419d5ef6","target_id":"f943043a-d62d-498b-bdc5-f1b0b11c4b4b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 387347fe-4237-48a8-9de1-8c8b419d5ef6 -\u003e f943043a-d62d-498b-bdc5-f1b0b11c4b4b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1345,"source_id":"387347fe-4237-48a8-9de1-8c8b419d5ef6","target_id":"40d5dba2-1cb5-4718-abb1-98493fe56ed1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 387347fe-4237-48a8-9de1-8c8b419d5ef6 -\u003e 40d5dba2-1cb5-4718-abb1-98493fe56ed1","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1346,"source_id":"303be0ec-64a2-41d5-9125-7dd46f7fa54a","target_id":"1da4608c-225c-48d5-b95d-719b36016a4c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 303be0ec-64a2-41d5-9125-7dd46f7fa54a -\u003e 1da4608c-225c-48d5-b95d-719b36016a4c","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1347,"source_id":"303be0ec-64a2-41d5-9125-7dd46f7fa54a","target_id":"5561e196-d14a-49b6-8d5f-b791c54024ea","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 303be0ec-64a2-41d5-9125-7dd46f7fa54a -\u003e 5561e196-d14a-49b6-8d5f-b791c54024ea","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1348,"source_id":"303be0ec-64a2-41d5-9125-7dd46f7fa54a","target_id":"f111c3f5-8bb1-4907-9385-bdb81402e1a4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 303be0ec-64a2-41d5-9125-7dd46f7fa54a -\u003e f111c3f5-8bb1-4907-9385-bdb81402e1a4","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1349,"source_id":"003fa99c-2fe9-4ccf-af4d-40cd84634a20","target_id":"d6686f19-13ba-4fe6-8c4e-3bf0fadd36be","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 003fa99c-2fe9-4ccf-af4d-40cd84634a20 -\u003e d6686f19-13ba-4fe6-8c4e-3bf0fadd36be","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1350,"source_id":"003fa99c-2fe9-4ccf-af4d-40cd84634a20","target_id":"2887e512-d32b-45b5-81fa-ee73748f8aea","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 003fa99c-2fe9-4ccf-af4d-40cd84634a20 -\u003e 2887e512-d32b-45b5-81fa-ee73748f8aea","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1351,"source_id":"003fa99c-2fe9-4ccf-af4d-40cd84634a20","target_id":"02d70c39-99f2-4361-80c5-e4cb4fcebcf7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 003fa99c-2fe9-4ccf-af4d-40cd84634a20 -\u003e 02d70c39-99f2-4361-80c5-e4cb4fcebcf7","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1352,"source_id":"804673b7-443f-4e85-8b92-5e308209d0f5","target_id":"19d79336-5e0d-49b5-b241-e4c9328883f6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 804673b7-443f-4e85-8b92-5e308209d0f5 -\u003e 19d79336-5e0d-49b5-b241-e4c9328883f6","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1353,"source_id":"804673b7-443f-4e85-8b92-5e308209d0f5","target_id":"447d8f86-c321-4cb4-a42b-efdc97bf8bcb","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 804673b7-443f-4e85-8b92-5e308209d0f5 -\u003e 447d8f86-c321-4cb4-a42b-efdc97bf8bcb","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1354,"source_id":"804673b7-443f-4e85-8b92-5e308209d0f5","target_id":"068e4e4c-7dbd-4cff-865f-e0c41c0081b6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 804673b7-443f-4e85-8b92-5e308209d0f5 -\u003e 068e4e4c-7dbd-4cff-865f-e0c41c0081b6","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1355,"source_id":"063cbaf7-e00b-4a07-a62d-df3b797bc32f","target_id":"711b6441-8164-44da-bd2f-1f55fed31484","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 063cbaf7-e00b-4a07-a62d-df3b797bc32f -\u003e 711b6441-8164-44da-bd2f-1f55fed31484","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1356,"source_id":"063cbaf7-e00b-4a07-a62d-df3b797bc32f","target_id":"b423af2b-e0e1-41c0-9519-985b5e106926","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 063cbaf7-e00b-4a07-a62d-df3b797bc32f -\u003e b423af2b-e0e1-41c0-9519-985b5e106926","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1357,"source_id":"063cbaf7-e00b-4a07-a62d-df3b797bc32f","target_id":"d9025f64-370a-414f-bf81-59ef536fdc14","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 063cbaf7-e00b-4a07-a62d-df3b797bc32f -\u003e d9025f64-370a-414f-bf81-59ef536fdc14","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1358,"source_id":"063cbaf7-e00b-4a07-a62d-df3b797bc32f","target_id":"88e03e88-d22c-4ebc-b071-74ecc7f65860","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 063cbaf7-e00b-4a07-a62d-df3b797bc32f -\u003e 88e03e88-d22c-4ebc-b071-74ecc7f65860","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1359,"source_id":"063cbaf7-e00b-4a07-a62d-df3b797bc32f","target_id":"766e4185-f81b-4a3e-b123-51fc4227719f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 063cbaf7-e00b-4a07-a62d-df3b797bc32f -\u003e 766e4185-f81b-4a3e-b123-51fc4227719f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1366,"source_id":"ce19faf8-ef6d-4718-82ce-772d2a15628a","target_id":"877b5a56-a3e2-40e9-ac6b-47d6b5cd4928","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ce19faf8-ef6d-4718-82ce-772d2a15628a -\u003e 877b5a56-a3e2-40e9-ac6b-47d6b5cd4928","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1367,"source_id":"ce19faf8-ef6d-4718-82ce-772d2a15628a","target_id":"6a83dfb1-6ad0-4b7b-be74-d2f703e150fe","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ce19faf8-ef6d-4718-82ce-772d2a15628a -\u003e 6a83dfb1-6ad0-4b7b-be74-d2f703e150fe","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1368,"source_id":"ce19faf8-ef6d-4718-82ce-772d2a15628a","target_id":"430b697e-305e-48c9-8a66-f1e5404d5551","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ce19faf8-ef6d-4718-82ce-772d2a15628a -\u003e 430b697e-305e-48c9-8a66-f1e5404d5551","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1369,"source_id":"ce19faf8-ef6d-4718-82ce-772d2a15628a","target_id":"5ba8ddd2-8eec-465e-a450-fc22d92bb196","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ce19faf8-ef6d-4718-82ce-772d2a15628a -\u003e 5ba8ddd2-8eec-465e-a450-fc22d92bb196","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1370,"source_id":"74831571-fcde-4baf-9bc1-e6e4f3a25a3f","target_id":"05c734b2-50d7-4311-b474-2f45ac700f17","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 74831571-fcde-4baf-9bc1-e6e4f3a25a3f -\u003e 05c734b2-50d7-4311-b474-2f45ac700f17","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1371,"source_id":"74831571-fcde-4baf-9bc1-e6e4f3a25a3f","target_id":"0cbefc41-fce4-4785-a0cf-f879dbca7135","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 74831571-fcde-4baf-9bc1-e6e4f3a25a3f -\u003e 0cbefc41-fce4-4785-a0cf-f879dbca7135","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1372,"source_id":"74831571-fcde-4baf-9bc1-e6e4f3a25a3f","target_id":"168033b1-8344-4ffe-b29c-e2d4c352b2dd","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 74831571-fcde-4baf-9bc1-e6e4f3a25a3f -\u003e 168033b1-8344-4ffe-b29c-e2d4c352b2dd","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1373,"source_id":"fc141673-0101-41e5-8fbd-185a232358e8","target_id":"5deae797-c878-4f81-a762-76a5629dbce3","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: fc141673-0101-41e5-8fbd-185a232358e8 -\u003e 5deae797-c878-4f81-a762-76a5629dbce3","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1374,"source_id":"fc141673-0101-41e5-8fbd-185a232358e8","target_id":"07dc10f4-cb06-4358-b164-7d949e3a0830","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: fc141673-0101-41e5-8fbd-185a232358e8 -\u003e 07dc10f4-cb06-4358-b164-7d949e3a0830","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1375,"source_id":"fc141673-0101-41e5-8fbd-185a232358e8","target_id":"1e76d9e8-b767-484b-9f9a-27b4b3233e33","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: fc141673-0101-41e5-8fbd-185a232358e8 -\u003e 1e76d9e8-b767-484b-9f9a-27b4b3233e33","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1376,"source_id":"fc141673-0101-41e5-8fbd-185a232358e8","target_id":"52f1e4a2-274c-4bd0-82a4-91140d41a8ad","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: fc141673-0101-41e5-8fbd-185a232358e8 -\u003e 52f1e4a2-274c-4bd0-82a4-91140d41a8ad","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1377,"source_id":"fc141673-0101-41e5-8fbd-185a232358e8","target_id":"cc8642e5-2540-46af-857a-5ec76a8aae5f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: fc141673-0101-41e5-8fbd-185a232358e8 -\u003e cc8642e5-2540-46af-857a-5ec76a8aae5f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1378,"source_id":"a6e195e7-dd42-43aa-abc7-67405e121060","target_id":"3735cc0b-3b69-4dcc-93e0-2ab16a38184b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a6e195e7-dd42-43aa-abc7-67405e121060 -\u003e 3735cc0b-3b69-4dcc-93e0-2ab16a38184b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1379,"source_id":"a6e195e7-dd42-43aa-abc7-67405e121060","target_id":"603898e3-2004-4267-a3db-25142259b3b2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a6e195e7-dd42-43aa-abc7-67405e121060 -\u003e 603898e3-2004-4267-a3db-25142259b3b2","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1380,"source_id":"a6e195e7-dd42-43aa-abc7-67405e121060","target_id":"86d3b799-a356-479d-9b12-06a16f032b4b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a6e195e7-dd42-43aa-abc7-67405e121060 -\u003e 86d3b799-a356-479d-9b12-06a16f032b4b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1381,"source_id":"a6e195e7-dd42-43aa-abc7-67405e121060","target_id":"ce75cf08-4a31-4449-8d9d-fa47d16365dd","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a6e195e7-dd42-43aa-abc7-67405e121060 -\u003e ce75cf08-4a31-4449-8d9d-fa47d16365dd","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1382,"source_id":"a15d849e-26b1-4748-b931-e66cd3927445","target_id":"3a808174-d192-4ad6-a71b-73424d1f308b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a15d849e-26b1-4748-b931-e66cd3927445 -\u003e 3a808174-d192-4ad6-a71b-73424d1f308b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1383,"source_id":"a15d849e-26b1-4748-b931-e66cd3927445","target_id":"3b586010-118d-457f-b891-4eb2cd2bc9ea","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a15d849e-26b1-4748-b931-e66cd3927445 -\u003e 3b586010-118d-457f-b891-4eb2cd2bc9ea","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1384,"source_id":"a15d849e-26b1-4748-b931-e66cd3927445","target_id":"3d89bb68-2ebe-4851-bbbf-1b81cfc75c11","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a15d849e-26b1-4748-b931-e66cd3927445 -\u003e 3d89bb68-2ebe-4851-bbbf-1b81cfc75c11","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1385,"source_id":"a15d849e-26b1-4748-b931-e66cd3927445","target_id":"6dedece1-3d65-4251-a3f7-3c6fd05657be","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a15d849e-26b1-4748-b931-e66cd3927445 -\u003e 6dedece1-3d65-4251-a3f7-3c6fd05657be","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1386,"source_id":"c3d8eae5-592e-4859-bdc3-81f5ebeda695","target_id":"5275f0b0-7594-4270-ba29-3af4db57be84","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c3d8eae5-592e-4859-bdc3-81f5ebeda695 -\u003e 5275f0b0-7594-4270-ba29-3af4db57be84","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1387,"source_id":"c3d8eae5-592e-4859-bdc3-81f5ebeda695","target_id":"71722d11-c614-4a85-bf0b-7d0c8ea1dad7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c3d8eae5-592e-4859-bdc3-81f5ebeda695 -\u003e 71722d11-c614-4a85-bf0b-7d0c8ea1dad7","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1388,"source_id":"c3d8eae5-592e-4859-bdc3-81f5ebeda695","target_id":"42e75f23-f50f-489e-b726-ce21c69c374b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c3d8eae5-592e-4859-bdc3-81f5ebeda695 -\u003e 42e75f23-f50f-489e-b726-ce21c69c374b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1389,"source_id":"c3d8eae5-592e-4859-bdc3-81f5ebeda695","target_id":"d319ae5e-0fa2-464d-8ec7-0452c636b895","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c3d8eae5-592e-4859-bdc3-81f5ebeda695 -\u003e d319ae5e-0fa2-464d-8ec7-0452c636b895","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1390,"source_id":"c3d8eae5-592e-4859-bdc3-81f5ebeda695","target_id":"7f9cbdb3-c4a1-45fe-a027-3ed45c0c98b2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c3d8eae5-592e-4859-bdc3-81f5ebeda695 -\u003e 7f9cbdb3-c4a1-45fe-a027-3ed45c0c98b2","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1394,"source_id":"d2c9ad66-a827-4029-b221-942b9f1ffff2","target_id":"c942c83e-0991-46e2-9447-45813b4ffa94","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d2c9ad66-a827-4029-b221-942b9f1ffff2 -\u003e c942c83e-0991-46e2-9447-45813b4ffa94","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1395,"source_id":"d2c9ad66-a827-4029-b221-942b9f1ffff2","target_id":"f09cdc5a-cc71-46ef-876a-5425ea0327fe","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d2c9ad66-a827-4029-b221-942b9f1ffff2 -\u003e f09cdc5a-cc71-46ef-876a-5425ea0327fe","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1396,"source_id":"d2c9ad66-a827-4029-b221-942b9f1ffff2","target_id":"94c58a7b-b072-4f9b-acbe-6e80f1cf7647","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d2c9ad66-a827-4029-b221-942b9f1ffff2 -\u003e 94c58a7b-b072-4f9b-acbe-6e80f1cf7647","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1397,"source_id":"0617f6de-bc78-4987-b57a-d81e6802ff10","target_id":"742cfe44-eb1e-4c34-98f0-b34ea70c5ee4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0617f6de-bc78-4987-b57a-d81e6802ff10 -\u003e 742cfe44-eb1e-4c34-98f0-b34ea70c5ee4","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1398,"source_id":"0617f6de-bc78-4987-b57a-d81e6802ff10","target_id":"1a27b90c-74db-48fd-81bd-c34bd255ec1a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0617f6de-bc78-4987-b57a-d81e6802ff10 -\u003e 1a27b90c-74db-48fd-81bd-c34bd255ec1a","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1399,"source_id":"0617f6de-bc78-4987-b57a-d81e6802ff10","target_id":"019082b2-299a-4ec3-9b07-6096f355ac31","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0617f6de-bc78-4987-b57a-d81e6802ff10 -\u003e 019082b2-299a-4ec3-9b07-6096f355ac31","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1401,"source_id":"4568681a-4970-4d2f-86cc-330effb87a9d","target_id":"e5b5081f-7d21-41e0-944a-5178465da066","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4568681a-4970-4d2f-86cc-330effb87a9d -\u003e e5b5081f-7d21-41e0-944a-5178465da066","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1402,"source_id":"4568681a-4970-4d2f-86cc-330effb87a9d","target_id":"d7b91880-5db8-4f6e-a907-09a610ada8e6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4568681a-4970-4d2f-86cc-330effb87a9d -\u003e d7b91880-5db8-4f6e-a907-09a610ada8e6","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1404,"source_id":"4568681a-4970-4d2f-86cc-330effb87a9d","target_id":"471312d7-c6bd-44db-8135-b041a3307f3f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4568681a-4970-4d2f-86cc-330effb87a9d -\u003e 471312d7-c6bd-44db-8135-b041a3307f3f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1405,"source_id":"eeeebcfe-e030-4d58-b0ad-7b86db5b5172","target_id":"7790558f-0a96-4611-98ed-ce93b8062382","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: eeeebcfe-e030-4d58-b0ad-7b86db5b5172 -\u003e 7790558f-0a96-4611-98ed-ce93b8062382","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1406,"source_id":"eeeebcfe-e030-4d58-b0ad-7b86db5b5172","target_id":"bd2f798b-6fe9-478a-9ec4-610204aeeeff","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: eeeebcfe-e030-4d58-b0ad-7b86db5b5172 -\u003e bd2f798b-6fe9-478a-9ec4-610204aeeeff","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1407,"source_id":"eeeebcfe-e030-4d58-b0ad-7b86db5b5172","target_id":"52d30486-a94a-47bc-a557-2cdd00db5138","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: eeeebcfe-e030-4d58-b0ad-7b86db5b5172 -\u003e 52d30486-a94a-47bc-a557-2cdd00db5138","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1408,"source_id":"eeeebcfe-e030-4d58-b0ad-7b86db5b5172","target_id":"b2a8d5c8-fa1b-4f1e-a177-e9bbdc52fdce","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: eeeebcfe-e030-4d58-b0ad-7b86db5b5172 -\u003e b2a8d5c8-fa1b-4f1e-a177-e9bbdc52fdce","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1409,"source_id":"a5e589d4-d359-4c6a-937d-772308efaa81","target_id":"2a4279e9-8563-47d9-9f71-91a4b9964c57","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a5e589d4-d359-4c6a-937d-772308efaa81 -\u003e 2a4279e9-8563-47d9-9f71-91a4b9964c57","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1410,"source_id":"a5e589d4-d359-4c6a-937d-772308efaa81","target_id":"20d50b39-4ee6-4447-a8ea-9315d64aa6c6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a5e589d4-d359-4c6a-937d-772308efaa81 -\u003e 20d50b39-4ee6-4447-a8ea-9315d64aa6c6","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1411,"source_id":"a5e589d4-d359-4c6a-937d-772308efaa81","target_id":"5fe7502f-3236-49bd-9b64-4ce0f5c991ce","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a5e589d4-d359-4c6a-937d-772308efaa81 -\u003e 5fe7502f-3236-49bd-9b64-4ce0f5c991ce","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1412,"source_id":"9b2bd429-f32e-4cb5-be78-92dc13b4fa70","target_id":"fd91b637-1310-48e1-940f-29f3fe60832e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9b2bd429-f32e-4cb5-be78-92dc13b4fa70 -\u003e fd91b637-1310-48e1-940f-29f3fe60832e","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1413,"source_id":"9b2bd429-f32e-4cb5-be78-92dc13b4fa70","target_id":"712c5e76-a1ab-47f7-9f60-b729f1164697","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9b2bd429-f32e-4cb5-be78-92dc13b4fa70 -\u003e 712c5e76-a1ab-47f7-9f60-b729f1164697","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1414,"source_id":"9b2bd429-f32e-4cb5-be78-92dc13b4fa70","target_id":"d297d929-a145-4707-82cb-323255f0ef05","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9b2bd429-f32e-4cb5-be78-92dc13b4fa70 -\u003e d297d929-a145-4707-82cb-323255f0ef05","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1415,"source_id":"9107bcd8-f768-4ca0-905e-34675135b448","target_id":"51dfa669-f053-418e-bfa0-39ea7f5af63f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9107bcd8-f768-4ca0-905e-34675135b448 -\u003e 51dfa669-f053-418e-bfa0-39ea7f5af63f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1416,"source_id":"9107bcd8-f768-4ca0-905e-34675135b448","target_id":"70b79193-4792-4c10-a728-7807045e44ad","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9107bcd8-f768-4ca0-905e-34675135b448 -\u003e 70b79193-4792-4c10-a728-7807045e44ad","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1417,"source_id":"9107bcd8-f768-4ca0-905e-34675135b448","target_id":"116d0eed-54bb-41f9-b5c0-63779ad2bc55","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9107bcd8-f768-4ca0-905e-34675135b448 -\u003e 116d0eed-54bb-41f9-b5c0-63779ad2bc55","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1418,"source_id":"9107bcd8-f768-4ca0-905e-34675135b448","target_id":"894883c0-de57-4ca3-89b0-908aa758c81c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9107bcd8-f768-4ca0-905e-34675135b448 -\u003e 894883c0-de57-4ca3-89b0-908aa758c81c","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1419,"source_id":"742cfe44-eb1e-4c34-98f0-b34ea70c5ee4","target_id":"875a096f-6990-48c8-9a58-6b25b53ba3b9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 742cfe44-eb1e-4c34-98f0-b34ea70c5ee4 -\u003e 875a096f-6990-48c8-9a58-6b25b53ba3b9","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1420,"source_id":"742cfe44-eb1e-4c34-98f0-b34ea70c5ee4","target_id":"0197ae18-c53e-4097-a1dc-f838fa44dd28","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 742cfe44-eb1e-4c34-98f0-b34ea70c5ee4 -\u003e 0197ae18-c53e-4097-a1dc-f838fa44dd28","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1421,"source_id":"2887e512-d32b-45b5-81fa-ee73748f8aea","target_id":"0a4a3e22-f70e-4c53-8919-cb185f2db113","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2887e512-d32b-45b5-81fa-ee73748f8aea -\u003e 0a4a3e22-f70e-4c53-8919-cb185f2db113","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1422,"source_id":"2887e512-d32b-45b5-81fa-ee73748f8aea","target_id":"46434d6d-23dc-475f-bfb7-1c3f8fe62325","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2887e512-d32b-45b5-81fa-ee73748f8aea -\u003e 46434d6d-23dc-475f-bfb7-1c3f8fe62325","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1423,"source_id":"2887e512-d32b-45b5-81fa-ee73748f8aea","target_id":"cad35cc6-2548-4bf8-ba3b-a861062c4332","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2887e512-d32b-45b5-81fa-ee73748f8aea -\u003e cad35cc6-2548-4bf8-ba3b-a861062c4332","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1424,"source_id":"76361208-bf89-4b44-9748-f8143863d49c","target_id":"6df78b08-2493-44df-a726-1492b2208603","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 76361208-bf89-4b44-9748-f8143863d49c -\u003e 6df78b08-2493-44df-a726-1492b2208603","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1425,"source_id":"76361208-bf89-4b44-9748-f8143863d49c","target_id":"ed559bfd-0527-413e-a783-7ffdda3cd03b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 76361208-bf89-4b44-9748-f8143863d49c -\u003e ed559bfd-0527-413e-a783-7ffdda3cd03b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1426,"source_id":"76361208-bf89-4b44-9748-f8143863d49c","target_id":"3ac19ad0-1d5e-4f68-86b4-c1ff5febef19","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 76361208-bf89-4b44-9748-f8143863d49c -\u003e 3ac19ad0-1d5e-4f68-86b4-c1ff5febef19","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1427,"source_id":"e4cb9c4e-b0e0-4a2e-96d7-288ea1a7ba86","target_id":"0651839c-1a4f-4a06-968e-991ddd90e5a8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e4cb9c4e-b0e0-4a2e-96d7-288ea1a7ba86 -\u003e 0651839c-1a4f-4a06-968e-991ddd90e5a8","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1428,"source_id":"e4cb9c4e-b0e0-4a2e-96d7-288ea1a7ba86","target_id":"18ad9731-a15d-4bf0-9c19-de571e4b9a87","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e4cb9c4e-b0e0-4a2e-96d7-288ea1a7ba86 -\u003e 18ad9731-a15d-4bf0-9c19-de571e4b9a87","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1429,"source_id":"e4cb9c4e-b0e0-4a2e-96d7-288ea1a7ba86","target_id":"38bea12a-9467-4d2a-8ff6-0d1f4246b221","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e4cb9c4e-b0e0-4a2e-96d7-288ea1a7ba86 -\u003e 38bea12a-9467-4d2a-8ff6-0d1f4246b221","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1430,"source_id":"0c774ddd-d820-4982-84c2-e396ababa803","target_id":"793d818e-c21e-4bf7-b8b2-159832759e8e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0c774ddd-d820-4982-84c2-e396ababa803 -\u003e 793d818e-c21e-4bf7-b8b2-159832759e8e","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1431,"source_id":"0c774ddd-d820-4982-84c2-e396ababa803","target_id":"f0c1d3fa-3481-49e1-8d20-13e85e72d715","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0c774ddd-d820-4982-84c2-e396ababa803 -\u003e f0c1d3fa-3481-49e1-8d20-13e85e72d715","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1432,"source_id":"d6546d25-2b85-4290-adde-19b5018a30e3","target_id":"6788ea2d-7323-4b4e-a9b3-e06ea8743154","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d6546d25-2b85-4290-adde-19b5018a30e3 -\u003e 6788ea2d-7323-4b4e-a9b3-e06ea8743154","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1433,"source_id":"d6546d25-2b85-4290-adde-19b5018a30e3","target_id":"0e759f36-f414-4f34-960b-0869878d3e7d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d6546d25-2b85-4290-adde-19b5018a30e3 -\u003e 0e759f36-f414-4f34-960b-0869878d3e7d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1434,"source_id":"d6546d25-2b85-4290-adde-19b5018a30e3","target_id":"bade36a8-290c-4347-91ab-7b546f4b3aac","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d6546d25-2b85-4290-adde-19b5018a30e3 -\u003e bade36a8-290c-4347-91ab-7b546f4b3aac","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1435,"source_id":"d6546d25-2b85-4290-adde-19b5018a30e3","target_id":"9532ad15-80ea-483b-a8a5-011bf0756a28","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d6546d25-2b85-4290-adde-19b5018a30e3 -\u003e 9532ad15-80ea-483b-a8a5-011bf0756a28","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1436,"source_id":"d6546d25-2b85-4290-adde-19b5018a30e3","target_id":"b89ce464-cf1c-46af-aab3-e34fd02aebb6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d6546d25-2b85-4290-adde-19b5018a30e3 -\u003e b89ce464-cf1c-46af-aab3-e34fd02aebb6","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1437,"source_id":"d6546d25-2b85-4290-adde-19b5018a30e3","target_id":"d32b616a-5dba-4c37-bbab-ab6fc77f7e8e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d6546d25-2b85-4290-adde-19b5018a30e3 -\u003e d32b616a-5dba-4c37-bbab-ab6fc77f7e8e","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1438,"source_id":"23c19f37-93ba-429a-b47b-2d2bdc9354dc","target_id":"6be8466c-f161-4330-bb7e-d2645011f1e4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 23c19f37-93ba-429a-b47b-2d2bdc9354dc -\u003e 6be8466c-f161-4330-bb7e-d2645011f1e4","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1439,"source_id":"23c19f37-93ba-429a-b47b-2d2bdc9354dc","target_id":"a342ceec-0617-428c-8b63-bb3cbf14e5b9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 23c19f37-93ba-429a-b47b-2d2bdc9354dc -\u003e a342ceec-0617-428c-8b63-bb3cbf14e5b9","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1440,"source_id":"23c19f37-93ba-429a-b47b-2d2bdc9354dc","target_id":"465aef1b-efcc-43ac-bd36-9c0373de8001","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 23c19f37-93ba-429a-b47b-2d2bdc9354dc -\u003e 465aef1b-efcc-43ac-bd36-9c0373de8001","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1441,"source_id":"23c19f37-93ba-429a-b47b-2d2bdc9354dc","target_id":"bef7ab2e-17f3-4122-8f3c-61c3bc3088eb","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 23c19f37-93ba-429a-b47b-2d2bdc9354dc -\u003e bef7ab2e-17f3-4122-8f3c-61c3bc3088eb","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1442,"source_id":"603898e3-2004-4267-a3db-25142259b3b2","target_id":"c8f9b14f-32c0-4117-bac6-dd345760e2e6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 603898e3-2004-4267-a3db-25142259b3b2 -\u003e c8f9b14f-32c0-4117-bac6-dd345760e2e6","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1443,"source_id":"603898e3-2004-4267-a3db-25142259b3b2","target_id":"1d63951f-cd45-44e3-87a2-92409b9a7e2d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 603898e3-2004-4267-a3db-25142259b3b2 -\u003e 1d63951f-cd45-44e3-87a2-92409b9a7e2d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1444,"source_id":"603898e3-2004-4267-a3db-25142259b3b2","target_id":"1d436f91-b0c2-4bf7-9fe5-e0efb1de13a7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 603898e3-2004-4267-a3db-25142259b3b2 -\u003e 1d436f91-b0c2-4bf7-9fe5-e0efb1de13a7","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1445,"source_id":"e5b5081f-7d21-41e0-944a-5178465da066","target_id":"ad4bee1f-9a9c-492e-a98c-8abb58a8fdc3","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e5b5081f-7d21-41e0-944a-5178465da066 -\u003e ad4bee1f-9a9c-492e-a98c-8abb58a8fdc3","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1446,"source_id":"e5b5081f-7d21-41e0-944a-5178465da066","target_id":"80a06058-0f75-4b52-9eaa-b8b20764d612","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e5b5081f-7d21-41e0-944a-5178465da066 -\u003e 80a06058-0f75-4b52-9eaa-b8b20764d612","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1447,"source_id":"e5b5081f-7d21-41e0-944a-5178465da066","target_id":"0acd135f-5f00-4bdb-bc34-956d870d51a7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e5b5081f-7d21-41e0-944a-5178465da066 -\u003e 0acd135f-5f00-4bdb-bc34-956d870d51a7","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1448,"source_id":"e5b5081f-7d21-41e0-944a-5178465da066","target_id":"15477812-7595-4f8d-a82a-4fa4dde2747c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e5b5081f-7d21-41e0-944a-5178465da066 -\u003e 15477812-7595-4f8d-a82a-4fa4dde2747c","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1449,"source_id":"6579034f-efa2-4e84-98a2-7b5dcbbb081e","target_id":"e35fe7d5-15ea-4211-a3f1-4f879de4710f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6579034f-efa2-4e84-98a2-7b5dcbbb081e -\u003e e35fe7d5-15ea-4211-a3f1-4f879de4710f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1450,"source_id":"6579034f-efa2-4e84-98a2-7b5dcbbb081e","target_id":"a4d07efc-2328-493e-9c85-ad96981b4a0d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6579034f-efa2-4e84-98a2-7b5dcbbb081e -\u003e a4d07efc-2328-493e-9c85-ad96981b4a0d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1451,"source_id":"6579034f-efa2-4e84-98a2-7b5dcbbb081e","target_id":"d25ed95b-8158-40cd-bea0-36c1c7e258f9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6579034f-efa2-4e84-98a2-7b5dcbbb081e -\u003e d25ed95b-8158-40cd-bea0-36c1c7e258f9","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1452,"source_id":"6579034f-efa2-4e84-98a2-7b5dcbbb081e","target_id":"da35c37b-1153-4546-9751-ef8a3ac57c44","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6579034f-efa2-4e84-98a2-7b5dcbbb081e -\u003e da35c37b-1153-4546-9751-ef8a3ac57c44","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1453,"source_id":"6579034f-efa2-4e84-98a2-7b5dcbbb081e","target_id":"3d96011f-daf4-40e6-bca1-e3490a1e7860","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6579034f-efa2-4e84-98a2-7b5dcbbb081e -\u003e 3d96011f-daf4-40e6-bca1-e3490a1e7860","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1454,"source_id":"6a83dfb1-6ad0-4b7b-be74-d2f703e150fe","target_id":"af3014f6-c4f6-4bfe-aec4-156c35edc01b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6a83dfb1-6ad0-4b7b-be74-d2f703e150fe -\u003e af3014f6-c4f6-4bfe-aec4-156c35edc01b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1455,"source_id":"6a83dfb1-6ad0-4b7b-be74-d2f703e150fe","target_id":"66b85aaa-b47b-4bde-ab17-2ff45298b2fa","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6a83dfb1-6ad0-4b7b-be74-d2f703e150fe -\u003e 66b85aaa-b47b-4bde-ab17-2ff45298b2fa","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1456,"source_id":"1a27b90c-74db-48fd-81bd-c34bd255ec1a","target_id":"3a78dcf6-2a26-4fd8-bb8b-e43174a78bb6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1a27b90c-74db-48fd-81bd-c34bd255ec1a -\u003e 3a78dcf6-2a26-4fd8-bb8b-e43174a78bb6","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1457,"source_id":"1a27b90c-74db-48fd-81bd-c34bd255ec1a","target_id":"3819148c-146f-4169-a3f4-9cf70e3845f4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1a27b90c-74db-48fd-81bd-c34bd255ec1a -\u003e 3819148c-146f-4169-a3f4-9cf70e3845f4","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1458,"source_id":"c646e112-10e4-4618-b290-d1bd1129c913","target_id":"eb17d43f-dd63-4a30-8829-a28cb4d7abd5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c646e112-10e4-4618-b290-d1bd1129c913 -\u003e eb17d43f-dd63-4a30-8829-a28cb4d7abd5","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1459,"source_id":"c646e112-10e4-4618-b290-d1bd1129c913","target_id":"f14282f3-81ce-4910-aa45-06345ac7fded","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c646e112-10e4-4618-b290-d1bd1129c913 -\u003e f14282f3-81ce-4910-aa45-06345ac7fded","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1460,"source_id":"c646e112-10e4-4618-b290-d1bd1129c913","target_id":"e735406b-56b3-4ed3-9872-850ca3f1d817","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c646e112-10e4-4618-b290-d1bd1129c913 -\u003e e735406b-56b3-4ed3-9872-850ca3f1d817","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1461,"source_id":"c646e112-10e4-4618-b290-d1bd1129c913","target_id":"180d0cbd-a5ca-493d-9e16-ad074de422f7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c646e112-10e4-4618-b290-d1bd1129c913 -\u003e 180d0cbd-a5ca-493d-9e16-ad074de422f7","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1462,"source_id":"02d70c39-99f2-4361-80c5-e4cb4fcebcf7","target_id":"c9d64d07-51fb-4f95-9065-6f3fbb43707d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 02d70c39-99f2-4361-80c5-e4cb4fcebcf7 -\u003e c9d64d07-51fb-4f95-9065-6f3fbb43707d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1463,"source_id":"02d70c39-99f2-4361-80c5-e4cb4fcebcf7","target_id":"b5d8c2de-e4dd-41c3-b6fb-ccfed9cc6007","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 02d70c39-99f2-4361-80c5-e4cb4fcebcf7 -\u003e b5d8c2de-e4dd-41c3-b6fb-ccfed9cc6007","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1464,"source_id":"02d70c39-99f2-4361-80c5-e4cb4fcebcf7","target_id":"a0d9a357-32d1-44a4-a4b0-d340c18a4dff","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 02d70c39-99f2-4361-80c5-e4cb4fcebcf7 -\u003e a0d9a357-32d1-44a4-a4b0-d340c18a4dff","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1465,"source_id":"1dbe65d5-1994-445e-aeed-7ca8a425006c","target_id":"fb7f51a9-b4f2-4928-b61b-7cdc4ef13713","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1dbe65d5-1994-445e-aeed-7ca8a425006c -\u003e fb7f51a9-b4f2-4928-b61b-7cdc4ef13713","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1466,"source_id":"1dbe65d5-1994-445e-aeed-7ca8a425006c","target_id":"44bd8148-c8e0-4623-bfcb-32396ac0bd3e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1dbe65d5-1994-445e-aeed-7ca8a425006c -\u003e 44bd8148-c8e0-4623-bfcb-32396ac0bd3e","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1467,"source_id":"1dbe65d5-1994-445e-aeed-7ca8a425006c","target_id":"e4574700-da89-4b6c-9cfc-8b4bd1b8a4ff","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1dbe65d5-1994-445e-aeed-7ca8a425006c -\u003e e4574700-da89-4b6c-9cfc-8b4bd1b8a4ff","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1468,"source_id":"40967690-1b17-417e-a87f-705788d6a788","target_id":"0e61102d-3011-4753-beb8-4c9e0e04149e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 40967690-1b17-417e-a87f-705788d6a788 -\u003e 0e61102d-3011-4753-beb8-4c9e0e04149e","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1469,"source_id":"40967690-1b17-417e-a87f-705788d6a788","target_id":"deafb08f-06f7-48f1-995d-0d652248a7e4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 40967690-1b17-417e-a87f-705788d6a788 -\u003e deafb08f-06f7-48f1-995d-0d652248a7e4","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1470,"source_id":"40967690-1b17-417e-a87f-705788d6a788","target_id":"0030f9ac-7de3-4709-a351-17470a4597ea","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 40967690-1b17-417e-a87f-705788d6a788 -\u003e 0030f9ac-7de3-4709-a351-17470a4597ea","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1471,"source_id":"f6c98e31-e00f-4acf-b95e-0e98fface5c5","target_id":"481369da-d759-445b-a0dd-cdc62566a219","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f6c98e31-e00f-4acf-b95e-0e98fface5c5 -\u003e 481369da-d759-445b-a0dd-cdc62566a219","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1472,"source_id":"f6c98e31-e00f-4acf-b95e-0e98fface5c5","target_id":"b425b514-387b-4ed6-8633-7f420d21cc75","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f6c98e31-e00f-4acf-b95e-0e98fface5c5 -\u003e b425b514-387b-4ed6-8633-7f420d21cc75","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1473,"source_id":"f6c98e31-e00f-4acf-b95e-0e98fface5c5","target_id":"22cb0edf-145a-4ac1-b530-0f2d35aebd7d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f6c98e31-e00f-4acf-b95e-0e98fface5c5 -\u003e 22cb0edf-145a-4ac1-b530-0f2d35aebd7d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1474,"source_id":"b25549e7-1a1b-4262-b87b-68f496c361e5","target_id":"c4d8e391-a6a6-420f-9087-0ac2b54b08ad","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b25549e7-1a1b-4262-b87b-68f496c361e5 -\u003e c4d8e391-a6a6-420f-9087-0ac2b54b08ad","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1475,"source_id":"b25549e7-1a1b-4262-b87b-68f496c361e5","target_id":"0b08475f-5111-4786-9af6-fd1200d8be57","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b25549e7-1a1b-4262-b87b-68f496c361e5 -\u003e 0b08475f-5111-4786-9af6-fd1200d8be57","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1476,"source_id":"b25549e7-1a1b-4262-b87b-68f496c361e5","target_id":"885458a5-fd69-46c4-abc1-e6851df34890","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b25549e7-1a1b-4262-b87b-68f496c361e5 -\u003e 885458a5-fd69-46c4-abc1-e6851df34890","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1477,"source_id":"b25549e7-1a1b-4262-b87b-68f496c361e5","target_id":"748bfabd-e76b-41f5-9ce8-07624bd06e7a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b25549e7-1a1b-4262-b87b-68f496c361e5 -\u003e 748bfabd-e76b-41f5-9ce8-07624bd06e7a","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1478,"source_id":"b25549e7-1a1b-4262-b87b-68f496c361e5","target_id":"1c5407f7-ee26-46e6-b082-c1e066573b4d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: b25549e7-1a1b-4262-b87b-68f496c361e5 -\u003e 1c5407f7-ee26-46e6-b082-c1e066573b4d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1479,"source_id":"86d3b799-a356-479d-9b12-06a16f032b4b","target_id":"102274b5-f1dc-438c-8d7e-1eaf7b6a9a71","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 86d3b799-a356-479d-9b12-06a16f032b4b -\u003e 102274b5-f1dc-438c-8d7e-1eaf7b6a9a71","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1480,"source_id":"86d3b799-a356-479d-9b12-06a16f032b4b","target_id":"21a428e9-0608-4e68-9179-f7aac4fdfdb1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 86d3b799-a356-479d-9b12-06a16f032b4b -\u003e 21a428e9-0608-4e68-9179-f7aac4fdfdb1","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1481,"source_id":"86d3b799-a356-479d-9b12-06a16f032b4b","target_id":"93b573e9-4eef-41c1-8627-e67e39372284","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 86d3b799-a356-479d-9b12-06a16f032b4b -\u003e 93b573e9-4eef-41c1-8627-e67e39372284","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1482,"source_id":"d7b91880-5db8-4f6e-a907-09a610ada8e6","target_id":"581d9a67-73b8-47f4-9c52-8d78f3834a23","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d7b91880-5db8-4f6e-a907-09a610ada8e6 -\u003e 581d9a67-73b8-47f4-9c52-8d78f3834a23","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1483,"source_id":"d7b91880-5db8-4f6e-a907-09a610ada8e6","target_id":"1889387a-f153-4e20-821c-e2ae3682b26d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d7b91880-5db8-4f6e-a907-09a610ada8e6 -\u003e 1889387a-f153-4e20-821c-e2ae3682b26d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1484,"source_id":"d7b91880-5db8-4f6e-a907-09a610ada8e6","target_id":"701392b9-78b8-48db-972e-c67a61311890","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d7b91880-5db8-4f6e-a907-09a610ada8e6 -\u003e 701392b9-78b8-48db-972e-c67a61311890","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1485,"source_id":"636325dc-bc8a-4bd6-9147-5ea10dfbdb58","target_id":"54347446-3f36-4bde-a3aa-fcc8886848d1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 636325dc-bc8a-4bd6-9147-5ea10dfbdb58 -\u003e 54347446-3f36-4bde-a3aa-fcc8886848d1","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1486,"source_id":"636325dc-bc8a-4bd6-9147-5ea10dfbdb58","target_id":"a0ecf4d2-f988-42d3-a5c1-212e99527d70","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 636325dc-bc8a-4bd6-9147-5ea10dfbdb58 -\u003e a0ecf4d2-f988-42d3-a5c1-212e99527d70","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1487,"source_id":"636325dc-bc8a-4bd6-9147-5ea10dfbdb58","target_id":"9a63a608-6170-4c1a-aa98-8478a14c9359","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 636325dc-bc8a-4bd6-9147-5ea10dfbdb58 -\u003e 9a63a608-6170-4c1a-aa98-8478a14c9359","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1488,"source_id":"019082b2-299a-4ec3-9b07-6096f355ac31","target_id":"6feb76e1-5555-4ef1-8095-6bb7f19945fe","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 019082b2-299a-4ec3-9b07-6096f355ac31 -\u003e 6feb76e1-5555-4ef1-8095-6bb7f19945fe","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1489,"source_id":"019082b2-299a-4ec3-9b07-6096f355ac31","target_id":"3a24ed08-8ca5-44a6-b931-2685db1fbc2f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 019082b2-299a-4ec3-9b07-6096f355ac31 -\u003e 3a24ed08-8ca5-44a6-b931-2685db1fbc2f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1490,"source_id":"cb8ab5c0-64d4-4f64-b62d-0f28cd29f12e","target_id":"ec95145e-40cb-421b-8cd8-a3a6101a7f17","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cb8ab5c0-64d4-4f64-b62d-0f28cd29f12e -\u003e ec95145e-40cb-421b-8cd8-a3a6101a7f17","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1491,"source_id":"cb8ab5c0-64d4-4f64-b62d-0f28cd29f12e","target_id":"e7e907eb-8f12-42a9-bde8-70388f0a36ef","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cb8ab5c0-64d4-4f64-b62d-0f28cd29f12e -\u003e e7e907eb-8f12-42a9-bde8-70388f0a36ef","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1492,"source_id":"cb8ab5c0-64d4-4f64-b62d-0f28cd29f12e","target_id":"a9030c1a-fc6b-4992-a431-ad3ad69e2a4f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: cb8ab5c0-64d4-4f64-b62d-0f28cd29f12e -\u003e a9030c1a-fc6b-4992-a431-ad3ad69e2a4f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1493,"source_id":"9d43b1ad-ce04-4422-b736-cc8edf592394","target_id":"f6f57334-59ea-417f-8a4d-d8e9ec52b6b5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9d43b1ad-ce04-4422-b736-cc8edf592394 -\u003e f6f57334-59ea-417f-8a4d-d8e9ec52b6b5","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1494,"source_id":"9d43b1ad-ce04-4422-b736-cc8edf592394","target_id":"5cc19fcb-de0c-4981-92e7-2ef78d574568","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9d43b1ad-ce04-4422-b736-cc8edf592394 -\u003e 5cc19fcb-de0c-4981-92e7-2ef78d574568","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1495,"source_id":"9d43b1ad-ce04-4422-b736-cc8edf592394","target_id":"27673d4c-18f7-4b6d-9b9f-0fd17623bfd6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9d43b1ad-ce04-4422-b736-cc8edf592394 -\u003e 27673d4c-18f7-4b6d-9b9f-0fd17623bfd6","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1496,"source_id":"9d43b1ad-ce04-4422-b736-cc8edf592394","target_id":"35c97c2a-d186-402b-ad2b-690c55c3ecf7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 9d43b1ad-ce04-4422-b736-cc8edf592394 -\u003e 35c97c2a-d186-402b-ad2b-690c55c3ecf7","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1497,"source_id":"094cefaf-bbca-448f-a303-c381ff621065","target_id":"8e26ea4f-1779-4832-a60b-0bfb57b9d601","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 094cefaf-bbca-448f-a303-c381ff621065 -\u003e 8e26ea4f-1779-4832-a60b-0bfb57b9d601","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1498,"source_id":"094cefaf-bbca-448f-a303-c381ff621065","target_id":"e0c7c0e3-087c-4853-8225-8027a1fc9d72","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 094cefaf-bbca-448f-a303-c381ff621065 -\u003e e0c7c0e3-087c-4853-8225-8027a1fc9d72","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1499,"source_id":"094cefaf-bbca-448f-a303-c381ff621065","target_id":"daeacd00-9e9a-4b04-8ebc-a1ee328c14ff","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 094cefaf-bbca-448f-a303-c381ff621065 -\u003e daeacd00-9e9a-4b04-8ebc-a1ee328c14ff","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1500,"source_id":"094cefaf-bbca-448f-a303-c381ff621065","target_id":"e93422fe-1e08-47d3-a26a-220bfd2dc740","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 094cefaf-bbca-448f-a303-c381ff621065 -\u003e e93422fe-1e08-47d3-a26a-220bfd2dc740","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1501,"source_id":"5ba8ddd2-8eec-465e-a450-fc22d92bb196","target_id":"3f6d1151-9229-4546-89f7-2db2952b68e8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 5ba8ddd2-8eec-465e-a450-fc22d92bb196 -\u003e 3f6d1151-9229-4546-89f7-2db2952b68e8","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1502,"source_id":"5ba8ddd2-8eec-465e-a450-fc22d92bb196","target_id":"02061ae3-3edf-4281-a095-d9f6ed89d3f4","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 5ba8ddd2-8eec-465e-a450-fc22d92bb196 -\u003e 02061ae3-3edf-4281-a095-d9f6ed89d3f4","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1503,"source_id":"37db4c74-0075-4d61-a617-961a2bb2b02c","target_id":"b19cb4d2-e3f3-4904-b675-97b0e9a7209b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 37db4c74-0075-4d61-a617-961a2bb2b02c -\u003e b19cb4d2-e3f3-4904-b675-97b0e9a7209b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1504,"source_id":"37db4c74-0075-4d61-a617-961a2bb2b02c","target_id":"31c68c10-2c5b-404d-911f-303fdecea54c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 37db4c74-0075-4d61-a617-961a2bb2b02c -\u003e 31c68c10-2c5b-404d-911f-303fdecea54c","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1505,"source_id":"37db4c74-0075-4d61-a617-961a2bb2b02c","target_id":"7d90e46e-f65b-4686-9b3c-52670f5c864b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 37db4c74-0075-4d61-a617-961a2bb2b02c -\u003e 7d90e46e-f65b-4686-9b3c-52670f5c864b","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1506,"source_id":"37db4c74-0075-4d61-a617-961a2bb2b02c","target_id":"db3c79fc-35bb-4178-8c4a-6adc34d30c51","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 37db4c74-0075-4d61-a617-961a2bb2b02c -\u003e db3c79fc-35bb-4178-8c4a-6adc34d30c51","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1507,"source_id":"471312d7-c6bd-44db-8135-b041a3307f3f","target_id":"1c16cc97-b397-4075-8585-3a7013372fde","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 471312d7-c6bd-44db-8135-b041a3307f3f -\u003e 1c16cc97-b397-4075-8585-3a7013372fde","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1508,"source_id":"471312d7-c6bd-44db-8135-b041a3307f3f","target_id":"9b6ce2f1-7c07-4f5a-a41b-ad09bb2b4748","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 471312d7-c6bd-44db-8135-b041a3307f3f -\u003e 9b6ce2f1-7c07-4f5a-a41b-ad09bb2b4748","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1509,"source_id":"0651839c-1a4f-4a06-968e-991ddd90e5a8","target_id":"627dbd19-e83f-45f8-9237-99c8d8d373d8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0651839c-1a4f-4a06-968e-991ddd90e5a8 -\u003e 627dbd19-e83f-45f8-9237-99c8d8d373d8","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1510,"source_id":"0651839c-1a4f-4a06-968e-991ddd90e5a8","target_id":"cb40aa69-fda3-4429-ab6f-d7f39e2213f9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0651839c-1a4f-4a06-968e-991ddd90e5a8 -\u003e cb40aa69-fda3-4429-ab6f-d7f39e2213f9","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1511,"source_id":"2a4279e9-8563-47d9-9f71-91a4b9964c57","target_id":"63a5129a-d045-4d19-ace1-5452184100f3","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2a4279e9-8563-47d9-9f71-91a4b9964c57 -\u003e 63a5129a-d045-4d19-ace1-5452184100f3","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1512,"source_id":"2a4279e9-8563-47d9-9f71-91a4b9964c57","target_id":"12e408dc-3b6e-4f97-93ca-1949ee8bcd04","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2a4279e9-8563-47d9-9f71-91a4b9964c57 -\u003e 12e408dc-3b6e-4f97-93ca-1949ee8bcd04","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1513,"source_id":"c8f9b14f-32c0-4117-bac6-dd345760e2e6","target_id":"1f7a3e10-52e7-4d11-b4e6-33e1b5381a41","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c8f9b14f-32c0-4117-bac6-dd345760e2e6 -\u003e 1f7a3e10-52e7-4d11-b4e6-33e1b5381a41","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1514,"source_id":"18ad9731-a15d-4bf0-9c19-de571e4b9a87","target_id":"de25e484-ea48-4307-bc89-f606b2cd0894","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 18ad9731-a15d-4bf0-9c19-de571e4b9a87 -\u003e de25e484-ea48-4307-bc89-f606b2cd0894","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1515,"source_id":"18ad9731-a15d-4bf0-9c19-de571e4b9a87","target_id":"7727b690-847c-42b0-bbf0-8107f2952869","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 18ad9731-a15d-4bf0-9c19-de571e4b9a87 -\u003e 7727b690-847c-42b0-bbf0-8107f2952869","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1516,"source_id":"20d50b39-4ee6-4447-a8ea-9315d64aa6c6","target_id":"f1427ab0-5c01-464f-8de0-5b49365d4e5f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 20d50b39-4ee6-4447-a8ea-9315d64aa6c6 -\u003e f1427ab0-5c01-464f-8de0-5b49365d4e5f","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1517,"source_id":"20d50b39-4ee6-4447-a8ea-9315d64aa6c6","target_id":"0ebc888a-93b4-465f-80b5-a4939fc4d487","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 20d50b39-4ee6-4447-a8ea-9315d64aa6c6 -\u003e 0ebc888a-93b4-465f-80b5-a4939fc4d487","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1518,"source_id":"1d63951f-cd45-44e3-87a2-92409b9a7e2d","target_id":"2fe4c058-0523-446b-b3e1-dd59a2c1536d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1d63951f-cd45-44e3-87a2-92409b9a7e2d -\u003e 2fe4c058-0523-446b-b3e1-dd59a2c1536d","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1519,"source_id":"21a428e9-0608-4e68-9179-f7aac4fdfdb1","target_id":"0f2ded6e-1226-4320-a357-8c54989fba03","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 21a428e9-0608-4e68-9179-f7aac4fdfdb1 -\u003e 0f2ded6e-1226-4320-a357-8c54989fba03","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1520,"source_id":"38bea12a-9467-4d2a-8ff6-0d1f4246b221","target_id":"409af96f-a3a0-4221-ace7-a04228d4a3d1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 38bea12a-9467-4d2a-8ff6-0d1f4246b221 -\u003e 409af96f-a3a0-4221-ace7-a04228d4a3d1","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1521,"source_id":"38bea12a-9467-4d2a-8ff6-0d1f4246b221","target_id":"5a456cd1-6974-4e5a-be4c-9ff055620233","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 38bea12a-9467-4d2a-8ff6-0d1f4246b221 -\u003e 5a456cd1-6974-4e5a-be4c-9ff055620233","gmt_create":"2025-12-26T02:38:31+08:00","gmt_modified":"2025-12-26T02:38:31+08:00"},{"id":1522,"source_id":"0651839c-1a4f-4a06-968e-991ddd90e5a8","target_id":"b698bd7e-c6ec-4ba2-85cc-c83480843723","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 0651839c-1a4f-4a06-968e-991ddd90e5a8 -\u003e b698bd7e-c6ec-4ba2-85cc-c83480843723","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1523,"source_id":"2a4279e9-8563-47d9-9f71-91a4b9964c57","target_id":"79a82e7b-0774-4c52-abbd-2680ff55d2ff","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2a4279e9-8563-47d9-9f71-91a4b9964c57 -\u003e 79a82e7b-0774-4c52-abbd-2680ff55d2ff","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1524,"source_id":"c8f9b14f-32c0-4117-bac6-dd345760e2e6","target_id":"7cc59d19-2ab9-48b8-96d6-bd193d05f787","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c8f9b14f-32c0-4117-bac6-dd345760e2e6 -\u003e 7cc59d19-2ab9-48b8-96d6-bd193d05f787","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1525,"source_id":"c8f9b14f-32c0-4117-bac6-dd345760e2e6","target_id":"12d17ea6-da6e-4c48-ba14-99ce7175386c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c8f9b14f-32c0-4117-bac6-dd345760e2e6 -\u003e 12d17ea6-da6e-4c48-ba14-99ce7175386c","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1526,"source_id":"c8f9b14f-32c0-4117-bac6-dd345760e2e6","target_id":"533f36a4-75e2-44f5-9f14-a0603e88878c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c8f9b14f-32c0-4117-bac6-dd345760e2e6 -\u003e 533f36a4-75e2-44f5-9f14-a0603e88878c","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1528,"source_id":"1d63951f-cd45-44e3-87a2-92409b9a7e2d","target_id":"c456e2c2-94e1-40f7-97b0-8c8c5909e1da","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1d63951f-cd45-44e3-87a2-92409b9a7e2d -\u003e c456e2c2-94e1-40f7-97b0-8c8c5909e1da","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1529,"source_id":"21a428e9-0608-4e68-9179-f7aac4fdfdb1","target_id":"e17edb1f-d955-4db5-9993-731414776b25","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 21a428e9-0608-4e68-9179-f7aac4fdfdb1 -\u003e e17edb1f-d955-4db5-9993-731414776b25","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1530,"source_id":"21a428e9-0608-4e68-9179-f7aac4fdfdb1","target_id":"3be4d28c-202d-427a-a36d-f7578aa626c2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 21a428e9-0608-4e68-9179-f7aac4fdfdb1 -\u003e 3be4d28c-202d-427a-a36d-f7578aa626c2","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1531,"source_id":"21a428e9-0608-4e68-9179-f7aac4fdfdb1","target_id":"ee9789b8-522f-419a-a1e7-8f0a03ec6e7d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 21a428e9-0608-4e68-9179-f7aac4fdfdb1 -\u003e ee9789b8-522f-419a-a1e7-8f0a03ec6e7d","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1532,"source_id":"38bea12a-9467-4d2a-8ff6-0d1f4246b221","target_id":"ba4f7804-366b-4b10-8ae8-bf7d65ebbba1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 38bea12a-9467-4d2a-8ff6-0d1f4246b221 -\u003e ba4f7804-366b-4b10-8ae8-bf7d65ebbba1","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"id":1533,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"0b661879cedb400c9b61d3daf683493f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java","gmt_create":"2026-01-29T21:48:29.2949005+08:00","gmt_modified":"2026-01-29T21:48:29.2949005+08:00"},{"id":1534,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"37aa79b4682c202fde07bb97de2205ac","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java","gmt_create":"2026-01-29T21:48:29.2960218+08:00","gmt_modified":"2026-01-29T21:48:29.2960218+08:00"},{"id":1535,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"09f7d92060102828f961c87f881c3712","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java","gmt_create":"2026-01-29T21:48:29.296646+08:00","gmt_modified":"2026-01-29T21:48:29.296646+08:00"},{"id":1536,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"70c29ebe25c4ef8b399ff6d9f0ebdcf5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java","gmt_create":"2026-01-29T21:48:29.2979047+08:00","gmt_modified":"2026-01-29T21:48:29.2979047+08:00"},{"id":1537,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"4e4727c0aacc3d9cc347c9917c686126","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java","gmt_create":"2026-01-29T21:48:29.2984231+08:00","gmt_modified":"2026-01-29T21:48:29.2984231+08:00"},{"id":1538,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"32bbf4f102dc3571bf9ebf326edbf8f4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java","gmt_create":"2026-01-29T21:48:29.2994209+08:00","gmt_modified":"2026-01-29T21:48:29.2994209+08:00"},{"id":1539,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"8b3157caf21880d8b0e7d859e41314d7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java","gmt_create":"2026-01-29T21:48:29.299921+08:00","gmt_modified":"2026-01-29T21:48:29.299921+08:00"},{"id":1540,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"13fd44fc6163676f8ebee5cc92f99bb0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java","gmt_create":"2026-01-29T21:48:29.3011122+08:00","gmt_modified":"2026-01-29T21:48:29.3011122+08:00"},{"id":1541,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"a2a3409cda4dd26ceacaa4179b8f539a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcConnectionInfo.java","gmt_create":"2026-01-29T21:48:29.3014168+08:00","gmt_modified":"2026-01-29T21:48:29.3014168+08:00"},{"id":1542,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"3fdd1b1df830bf6cf2c3ca092dd6a111","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java","gmt_create":"2026-01-29T21:48:29.3019169+08:00","gmt_modified":"2026-01-29T21:48:29.3019169+08:00"},{"id":1543,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"6be402d159c79d233b2f9021df5ace47","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java","gmt_create":"2026-01-29T21:48:29.3019169+08:00","gmt_modified":"2026-01-29T21:48:29.3019169+08:00"},{"id":1544,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"7a80cd0418c6ade29f7450ba58bd7eae","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java","gmt_create":"2026-01-29T21:48:29.3024685+08:00","gmt_modified":"2026-01-29T21:48:29.3024685+08:00"},{"id":1545,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"2a888d19dfa6b98f3cd92f53a331460d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java","gmt_create":"2026-01-29T21:48:29.303561+08:00","gmt_modified":"2026-01-29T21:48:29.303561+08:00"},{"id":1546,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"3c383b66697430c3aabded26176c698a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java","gmt_create":"2026-01-29T21:48:29.3047738+08:00","gmt_modified":"2026-01-29T21:48:29.3047738+08:00"},{"id":1547,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"1525e304646696f9e56b733b2ee0f7d9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java","gmt_create":"2026-01-29T21:48:29.3053771+08:00","gmt_modified":"2026-01-29T21:48:29.3053771+08:00"},{"id":1548,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"b47d0a2071e708e116371678d9b4b6f8","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java","gmt_create":"2026-01-29T21:48:29.3058907+08:00","gmt_modified":"2026-01-29T21:48:29.3058907+08:00"},{"id":1549,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"f724dc8d352d041d1310a330bf104c58","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java","gmt_create":"2026-01-29T21:48:29.3065098+08:00","gmt_modified":"2026-01-29T21:48:29.3065098+08:00"},{"id":1550,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"ba0301372f1e73a6524ba558633ce3d7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/ConfigConstants.java","gmt_create":"2026-01-29T21:48:29.3070199+08:00","gmt_modified":"2026-01-29T21:48:29.3070199+08:00"},{"id":1551,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"0b661879cedb400c9b61d3daf683493f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java","gmt_create":"2026-01-29T21:49:21.9085024+08:00","gmt_modified":"2026-01-29T21:49:21.9085024+08:00"},{"id":1552,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"37aa79b4682c202fde07bb97de2205ac","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java","gmt_create":"2026-01-29T21:49:21.9088176+08:00","gmt_modified":"2026-01-29T21:49:21.9088176+08:00"},{"id":1553,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"70c29ebe25c4ef8b399ff6d9f0ebdcf5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java","gmt_create":"2026-01-29T21:49:21.909333+08:00","gmt_modified":"2026-01-29T21:49:21.909333+08:00"},{"id":1554,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"09f7d92060102828f961c87f881c3712","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java","gmt_create":"2026-01-29T21:49:21.9094718+08:00","gmt_modified":"2026-01-29T21:49:21.9094718+08:00"},{"id":1555,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"e4e9a8401a3a0641202516ad63661495","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java","gmt_create":"2026-01-29T21:49:21.9099398+08:00","gmt_modified":"2026-01-29T21:49:21.9099398+08:00"},{"id":1556,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"32bbf4f102dc3571bf9ebf326edbf8f4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java","gmt_create":"2026-01-29T21:49:21.9103329+08:00","gmt_modified":"2026-01-29T21:49:21.9103329+08:00"},{"id":1557,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"8b3157caf21880d8b0e7d859e41314d7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java","gmt_create":"2026-01-29T21:49:21.9103329+08:00","gmt_modified":"2026-01-29T21:49:21.9103329+08:00"},{"id":1558,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"13fd44fc6163676f8ebee5cc92f99bb0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java","gmt_create":"2026-01-29T21:49:21.910833+08:00","gmt_modified":"2026-01-29T21:49:21.910833+08:00"},{"id":1559,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"98d07543ade7080eb0286f7e45dfc334","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java","gmt_create":"2026-01-29T21:49:21.910833+08:00","gmt_modified":"2026-01-29T21:49:21.910833+08:00"},{"id":1560,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"fb8253d4c7d179918b6aca3e77ad9933","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java","gmt_create":"2026-01-29T21:49:21.9113345+08:00","gmt_modified":"2026-01-29T21:49:21.9113345+08:00"},{"id":1561,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"6be402d159c79d233b2f9021df5ace47","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java","gmt_create":"2026-01-29T21:49:21.9118329+08:00","gmt_modified":"2026-01-29T21:49:21.9118329+08:00"},{"id":1562,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"7a80cd0418c6ade29f7450ba58bd7eae","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java","gmt_create":"2026-01-29T21:49:21.9118329+08:00","gmt_modified":"2026-01-29T21:49:21.9118329+08:00"},{"id":1563,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"1114b0c39352aeb37b7098e8dc051054","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java","gmt_create":"2026-01-29T21:49:21.9123321+08:00","gmt_modified":"2026-01-29T21:49:21.9123321+08:00"},{"id":1564,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"2a888d19dfa6b98f3cd92f53a331460d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java","gmt_create":"2026-01-29T21:49:21.9125561+08:00","gmt_modified":"2026-01-29T21:49:21.9125561+08:00"},{"id":1565,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"392a5a4399de01ca2207faad3b87fd67","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-clickhouse/src/main/java/io/datavines/connector/plugin/ClickHouseConnector.java","gmt_create":"2026-01-29T21:49:21.9128321+08:00","gmt_modified":"2026-01-29T21:49:21.9128321+08:00"},{"id":1566,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"3c383b66697430c3aabded26176c698a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java","gmt_create":"2026-01-29T21:49:21.9133327+08:00","gmt_modified":"2026-01-29T21:49:21.9133327+08:00"},{"id":1567,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"4b6b7ea4410be6c0507bed82ae92cf67","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDialect.java","gmt_create":"2026-01-29T21:49:21.9133327+08:00","gmt_modified":"2026-01-29T21:49:21.9133327+08:00"},{"id":1568,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"f724dc8d352d041d1310a330bf104c58","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java","gmt_create":"2026-01-29T21:49:21.9138325+08:00","gmt_modified":"2026-01-29T21:49:21.9138325+08:00"},{"id":1569,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"1525e304646696f9e56b733b2ee0f7d9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java","gmt_create":"2026-01-29T21:49:21.914333+08:00","gmt_modified":"2026-01-29T21:49:21.914333+08:00"},{"id":1570,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"bdd667272cc3195e320af49a3cec6735","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisExecutor.java","gmt_create":"2026-01-29T21:49:21.914333+08:00","gmt_modified":"2026-01-29T21:49:21.914333+08:00"},{"id":1571,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"b47d0a2071e708e116371678d9b4b6f8","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java","gmt_create":"2026-01-29T21:49:21.9148321+08:00","gmt_modified":"2026-01-29T21:49:21.9148321+08:00"},{"id":1572,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"fcf6660d99d891324d3466506759f9ee","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java","gmt_create":"2026-01-29T21:49:21.9153333+08:00","gmt_modified":"2026-01-29T21:49:21.9153333+08:00"},{"id":1573,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"814810e1e2a875e8055c149185d2ca88","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java#24-72","gmt_create":"2026-01-29T21:49:21.915835+08:00","gmt_modified":"2026-01-29T21:49:21.915835+08:00"},{"id":1574,"source_id":"0b661879cedb400c9b61d3daf683493f","target_id":"814810e1e2a875e8055c149185d2ca88","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-72","gmt_create":"2026-01-29T21:49:21.9163391+08:00","gmt_modified":"2026-01-29T21:49:21.9163391+08:00"},{"id":1575,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"f9ae254d631b05eefcc5414aa2baa65a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java#42-283","gmt_create":"2026-01-29T21:49:21.9173549+08:00","gmt_modified":"2026-01-29T21:49:21.9173549+08:00"},{"id":1576,"source_id":"32bbf4f102dc3571bf9ebf326edbf8f4","target_id":"f9ae254d631b05eefcc5414aa2baa65a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-283","gmt_create":"2026-01-29T21:49:21.945894+08:00","gmt_modified":"2026-01-29T21:49:21.945894+08:00"},{"id":1577,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"19cf3abc64d0f832b3fc2241ad064717","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java#28-45","gmt_create":"2026-01-29T21:49:21.9493663+08:00","gmt_modified":"2026-01-29T21:49:21.9493663+08:00"},{"id":1578,"source_id":"6be402d159c79d233b2f9021df5ace47","target_id":"19cf3abc64d0f832b3fc2241ad064717","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-45","gmt_create":"2026-01-29T21:49:21.9499658+08:00","gmt_modified":"2026-01-29T21:49:21.9499658+08:00"},{"id":1579,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"2d56d5b0b4a327e2f8267aeac2765f1f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java#28-54","gmt_create":"2026-01-29T21:49:21.9505048+08:00","gmt_modified":"2026-01-29T21:49:21.9505048+08:00"},{"id":1580,"source_id":"7a80cd0418c6ade29f7450ba58bd7eae","target_id":"2d56d5b0b4a327e2f8267aeac2765f1f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-54","gmt_create":"2026-01-29T21:49:21.9510053+08:00","gmt_modified":"2026-01-29T21:49:21.9510053+08:00"},{"id":1581,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"8b827b3d0cb5a8c0d43c0b422bcba4cd","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java#28-59","gmt_create":"2026-01-29T21:49:21.9510053+08:00","gmt_modified":"2026-01-29T21:49:21.9510053+08:00"},{"id":1582,"source_id":"1114b0c39352aeb37b7098e8dc051054","target_id":"8b827b3d0cb5a8c0d43c0b422bcba4cd","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-59","gmt_create":"2026-01-29T21:49:21.9515636+08:00","gmt_modified":"2026-01-29T21:49:21.9515636+08:00"},{"id":1583,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"80a2d925ae81604e425cb61eee2a5949","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java#28-75","gmt_create":"2026-01-29T21:49:21.9520717+08:00","gmt_modified":"2026-01-29T21:49:21.9520717+08:00"},{"id":1584,"source_id":"2a888d19dfa6b98f3cd92f53a331460d","target_id":"80a2d925ae81604e425cb61eee2a5949","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-75","gmt_create":"2026-01-29T21:49:21.9520717+08:00","gmt_modified":"2026-01-29T21:49:21.9520717+08:00"},{"id":1585,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"b9f27ead9db0af93d7434b5026712f07","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-clickhouse/src/main/java/io/datavines/connector/plugin/ClickHouseConnector.java#27-46","gmt_create":"2026-01-29T21:49:21.9526084+08:00","gmt_modified":"2026-01-29T21:49:21.9526084+08:00"},{"id":1586,"source_id":"392a5a4399de01ca2207faad3b87fd67","target_id":"b9f27ead9db0af93d7434b5026712f07","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 27-46","gmt_create":"2026-01-29T21:49:21.9531386+08:00","gmt_modified":"2026-01-29T21:49:21.9531386+08:00"},{"id":1587,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"ad3a1bd5e995be8af6e9c70958ffbbae","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#40-251","gmt_create":"2026-01-29T21:49:21.9536635+08:00","gmt_modified":"2026-01-29T21:49:21.9536635+08:00"},{"id":1588,"source_id":"3c383b66697430c3aabded26176c698a","target_id":"ad3a1bd5e995be8af6e9c70958ffbbae","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 40-251","gmt_create":"2026-01-29T21:49:21.9541906+08:00","gmt_modified":"2026-01-29T21:49:21.9541906+08:00"},{"id":1589,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"4dab60fa9d135a3a3f8767779fe7fa6f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java#33-150","gmt_create":"2026-01-29T21:49:21.9547141+08:00","gmt_modified":"2026-01-29T21:49:21.9547141+08:00"},{"id":1590,"source_id":"37aa79b4682c202fde07bb97de2205ac","target_id":"4dab60fa9d135a3a3f8767779fe7fa6f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-150","gmt_create":"2026-01-29T21:49:21.9552683+08:00","gmt_modified":"2026-01-29T21:49:21.9552683+08:00"},{"id":1591,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"f6753f13f7cf9daaccb1defb4eb22781","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java#33-75","gmt_create":"2026-01-29T21:49:21.9557936+08:00","gmt_modified":"2026-01-29T21:49:21.9557936+08:00"},{"id":1592,"source_id":"8b3157caf21880d8b0e7d859e41314d7","target_id":"f6753f13f7cf9daaccb1defb4eb22781","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 33-75","gmt_create":"2026-01-29T21:49:21.9557936+08:00","gmt_modified":"2026-01-29T21:49:21.9557936+08:00"},{"id":1593,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"561dea64cc76d5df6c5352fb74fc7569","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDialect.java#19-25","gmt_create":"2026-01-29T21:49:21.9557936+08:00","gmt_modified":"2026-01-29T21:49:21.9557936+08:00"},{"id":1594,"source_id":"4b6b7ea4410be6c0507bed82ae92cf67","target_id":"561dea64cc76d5df6c5352fb74fc7569","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-25","gmt_create":"2026-01-29T21:49:21.9568019+08:00","gmt_modified":"2026-01-29T21:49:21.9568019+08:00"},{"id":1595,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"f0ca1df1a5911701ee393be59add314d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java#24-46","gmt_create":"2026-01-29T21:49:21.9576252+08:00","gmt_modified":"2026-01-29T21:49:21.9576252+08:00"},{"id":1596,"source_id":"70c29ebe25c4ef8b399ff6d9f0ebdcf5","target_id":"f0ca1df1a5911701ee393be59add314d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-46","gmt_create":"2026-01-29T21:49:21.9579092+08:00","gmt_modified":"2026-01-29T21:49:21.9579092+08:00"},{"id":1597,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"5080e00c0ba0973d12721f8a9139d20d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java#34-116","gmt_create":"2026-01-29T21:49:21.9581504+08:00","gmt_modified":"2026-01-29T21:49:21.9581504+08:00"},{"id":1598,"source_id":"13fd44fc6163676f8ebee5cc92f99bb0","target_id":"5080e00c0ba0973d12721f8a9139d20d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 34-116","gmt_create":"2026-01-29T21:49:21.95868+08:00","gmt_modified":"2026-01-29T21:49:21.95868+08:00"},{"id":1599,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"805c6ce717dfa901e13c631bf6c9b5bc","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisExecutor.java#24-35","gmt_create":"2026-01-29T21:49:21.9592125+08:00","gmt_modified":"2026-01-29T21:49:21.9592125+08:00"},{"id":1600,"source_id":"bdd667272cc3195e320af49a3cec6735","target_id":"805c6ce717dfa901e13c631bf6c9b5bc","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-35","gmt_create":"2026-01-29T21:49:21.9597357+08:00","gmt_modified":"2026-01-29T21:49:21.9597357+08:00"},{"id":1601,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"8046f83719b4709b42935e4b518c3923","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java#30-47","gmt_create":"2026-01-29T21:49:21.9607816+08:00","gmt_modified":"2026-01-29T21:49:21.9607816+08:00"},{"id":1602,"source_id":"09f7d92060102828f961c87f881c3712","target_id":"8046f83719b4709b42935e4b518c3923","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 30-47","gmt_create":"2026-01-29T21:49:21.9607816+08:00","gmt_modified":"2026-01-29T21:49:21.9607816+08:00"},{"id":1603,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"2aba75aec896281e18c1821cafc696d9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java#32-88","gmt_create":"2026-01-29T21:49:21.9612944+08:00","gmt_modified":"2026-01-29T21:49:21.9612944+08:00"},{"id":1604,"source_id":"98d07543ade7080eb0286f7e45dfc334","target_id":"2aba75aec896281e18c1821cafc696d9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-88","gmt_create":"2026-01-29T21:49:21.9618155+08:00","gmt_modified":"2026-01-29T21:49:21.9618155+08:00"},{"id":1605,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"381316af739d43973d0f5a5ad0d5aaf3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#72-85","gmt_create":"2026-01-29T21:49:21.9644743+08:00","gmt_modified":"2026-01-29T21:49:21.9644743+08:00"},{"id":1606,"source_id":"3c383b66697430c3aabded26176c698a","target_id":"381316af739d43973d0f5a5ad0d5aaf3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 72-85","gmt_create":"2026-01-29T21:49:21.9651012+08:00","gmt_modified":"2026-01-29T21:49:21.9651012+08:00"},{"id":1607,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"9115e5d018e2a599c9783f2151a77f9d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java#206-249","gmt_create":"2026-01-29T21:49:21.9651774+08:00","gmt_modified":"2026-01-29T21:49:21.9651774+08:00"},{"id":1608,"source_id":"3c383b66697430c3aabded26176c698a","target_id":"9115e5d018e2a599c9783f2151a77f9d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 206-249","gmt_create":"2026-01-29T21:49:21.9656784+08:00","gmt_modified":"2026-01-29T21:49:21.9656784+08:00"},{"id":1609,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"ef0659592beb83e1abc532bb877b164a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java#25-59","gmt_create":"2026-01-29T21:49:21.9656784+08:00","gmt_modified":"2026-01-29T21:49:21.9656784+08:00"},{"id":1610,"source_id":"f724dc8d352d041d1310a330bf104c58","target_id":"ef0659592beb83e1abc532bb877b164a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-59","gmt_create":"2026-01-29T21:49:21.9666921+08:00","gmt_modified":"2026-01-29T21:49:21.9666921+08:00"},{"id":1611,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"38b45138543833f148982d52908c6f91","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java#23-62","gmt_create":"2026-01-29T21:49:21.9666921+08:00","gmt_modified":"2026-01-29T21:49:21.9666921+08:00"},{"id":1612,"source_id":"1525e304646696f9e56b733b2ee0f7d9","target_id":"38b45138543833f148982d52908c6f91","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 23-62","gmt_create":"2026-01-29T21:49:21.9675247+08:00","gmt_modified":"2026-01-29T21:49:21.9675247+08:00"},{"id":1613,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"05c52b772dc3dcb9b030a651d6aa946c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java#25-51","gmt_create":"2026-01-29T21:49:21.9677211+08:00","gmt_modified":"2026-01-29T21:49:21.9677211+08:00"},{"id":1614,"source_id":"b47d0a2071e708e116371678d9b4b6f8","target_id":"05c52b772dc3dcb9b030a651d6aa946c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-51","gmt_create":"2026-01-29T21:49:21.9681807+08:00","gmt_modified":"2026-01-29T21:49:21.9681807+08:00"},{"id":1615,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"89cc9187af0b648ba39e93d5725636d4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java#21-48","gmt_create":"2026-01-29T21:49:21.9686792+08:00","gmt_modified":"2026-01-29T21:49:21.9686792+08:00"},{"id":1616,"source_id":"fcf6660d99d891324d3466506759f9ee","target_id":"89cc9187af0b648ba39e93d5725636d4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 21-48","gmt_create":"2026-01-29T21:49:21.9691787+08:00","gmt_modified":"2026-01-29T21:49:21.9691787+08:00"},{"id":1617,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"0a09dfdafd728bc656da6e0f2c7e8fb0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java#19-24","gmt_create":"2026-01-29T21:49:21.9696783+08:00","gmt_modified":"2026-01-29T21:49:21.9696783+08:00"},{"id":1618,"source_id":"e4e9a8401a3a0641202516ad63661495","target_id":"0a09dfdafd728bc656da6e0f2c7e8fb0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 19-24","gmt_create":"2026-01-29T21:49:21.9696783+08:00","gmt_modified":"2026-01-29T21:49:21.9696783+08:00"},{"id":1619,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"d59fb437d7c5b71dd7534adb6d21109f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java#36-150","gmt_create":"2026-01-29T21:49:21.9701817+08:00","gmt_modified":"2026-01-29T21:49:21.9701817+08:00"},{"id":1620,"source_id":"fb8253d4c7d179918b6aca3e77ad9933","target_id":"d59fb437d7c5b71dd7534adb6d21109f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-150","gmt_create":"2026-01-29T21:49:21.9706822+08:00","gmt_modified":"2026-01-29T21:49:21.9706822+08:00"},{"id":1621,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"fb17021b483fcb4a4bf766b794642ad3","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java#35-42","gmt_create":"2026-01-29T21:49:21.9716796+08:00","gmt_modified":"2026-01-29T21:49:21.9716796+08:00"},{"id":1622,"source_id":"f724dc8d352d041d1310a330bf104c58","target_id":"fb17021b483fcb4a4bf766b794642ad3","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 35-42","gmt_create":"2026-01-29T21:49:21.9721794+08:00","gmt_modified":"2026-01-29T21:49:21.9721794+08:00"},{"id":1623,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"1e84740a4cc545f9064a8bbfc9510252","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java#28-49","gmt_create":"2026-01-29T21:49:21.9721794+08:00","gmt_modified":"2026-01-29T21:49:21.9721794+08:00"},{"id":1624,"source_id":"b47d0a2071e708e116371678d9b4b6f8","target_id":"1e84740a4cc545f9064a8bbfc9510252","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 28-49","gmt_create":"2026-01-29T21:49:21.9726791+08:00","gmt_modified":"2026-01-29T21:49:21.9726791+08:00"},{"id":1625,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"991962c9ca7bad79a3806e4eb014a15c","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java#38-60","gmt_create":"2026-01-29T21:49:21.9732005+08:00","gmt_modified":"2026-01-29T21:49:21.9732005+08:00"},{"id":1626,"source_id":"1525e304646696f9e56b733b2ee0f7d9","target_id":"991962c9ca7bad79a3806e4eb014a15c","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 38-60","gmt_create":"2026-01-29T21:49:21.9737305+08:00","gmt_modified":"2026-01-29T21:49:21.9737305+08:00"},{"id":1627,"source_id":"d50d63e5-3a8f-4a16-8d03-e59d23082f71","target_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d50d63e5-3a8f-4a16-8d03-e59d23082f71 -\u003e 93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","gmt_create":"2026-01-29T21:51:04.8176706+08:00","gmt_modified":"2026-01-29T21:51:04.8176706+08:00"},{"id":1628,"source_id":"13baf602-8637-4c51-92f1-25bbcbb79482","target_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 13baf602-8637-4c51-92f1-25bbcbb79482 -\u003e 3e4f1072-e709-4860-9a6f-6dbf5f55fc57","gmt_create":"2026-01-29T21:51:04.8201482+08:00","gmt_modified":"2026-01-29T21:51:04.8201482+08:00"},{"id":1630,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"7fd23d79-a4be-4774-95d6-d4209e24bf4e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 93eeddb1-5a4a-4bf3-a0ff-966d57beb5da -\u003e 7fd23d79-a4be-4774-95d6-d4209e24bf4e","gmt_create":"2026-01-29T21:51:04.8301556+08:00","gmt_modified":"2026-01-29T21:51:04.8301556+08:00"},{"id":1631,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"89883bfd-09a9-498a-a47e-a3663ffa0fac","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 93eeddb1-5a4a-4bf3-a0ff-966d57beb5da -\u003e 89883bfd-09a9-498a-a47e-a3663ffa0fac","gmt_create":"2026-01-29T21:51:04.8306748+08:00","gmt_modified":"2026-01-29T21:51:04.8306748+08:00"},{"id":1632,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"319f1a59-2575-486f-8e89-59f66b353c94","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 93eeddb1-5a4a-4bf3-a0ff-966d57beb5da -\u003e 319f1a59-2575-486f-8e89-59f66b353c94","gmt_create":"2026-01-29T21:51:04.8306748+08:00","gmt_modified":"2026-01-29T21:51:04.8306748+08:00"},{"id":1633,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"2cee7d06-6eea-47ca-bfdf-a4f9f3b7b98d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 93eeddb1-5a4a-4bf3-a0ff-966d57beb5da -\u003e 2cee7d06-6eea-47ca-bfdf-a4f9f3b7b98d","gmt_create":"2026-01-29T21:51:04.8315898+08:00","gmt_modified":"2026-01-29T21:51:04.8315898+08:00"},{"id":1634,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"eadca672-1598-41ce-a817-87a2c5820792","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 93eeddb1-5a4a-4bf3-a0ff-966d57beb5da -\u003e eadca672-1598-41ce-a817-87a2c5820792","gmt_create":"2026-01-29T21:51:04.8321155+08:00","gmt_modified":"2026-01-29T21:51:04.8321155+08:00"},{"id":1635,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"d99205fd-d456-4d7d-91b1-4141f45dda95","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 93eeddb1-5a4a-4bf3-a0ff-966d57beb5da -\u003e d99205fd-d456-4d7d-91b1-4141f45dda95","gmt_create":"2026-01-29T21:51:04.8326156+08:00","gmt_modified":"2026-01-29T21:51:04.8326156+08:00"},{"id":1636,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"9107bcd8-f768-4ca0-905e-34675135b448","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3e4f1072-e709-4860-9a6f-6dbf5f55fc57 -\u003e 9107bcd8-f768-4ca0-905e-34675135b448","gmt_create":"2026-01-29T21:51:04.8377449+08:00","gmt_modified":"2026-01-29T21:51:04.8377449+08:00"},{"id":1637,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"6579034f-efa2-4e84-98a2-7b5dcbbb081e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3e4f1072-e709-4860-9a6f-6dbf5f55fc57 -\u003e 6579034f-efa2-4e84-98a2-7b5dcbbb081e","gmt_create":"2026-01-29T21:51:04.8388035+08:00","gmt_modified":"2026-01-29T21:51:04.8388035+08:00"},{"id":1638,"source_id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","target_id":"636325dc-bc8a-4bd6-9147-5ea10dfbdb58","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3e4f1072-e709-4860-9a6f-6dbf5f55fc57 -\u003e 636325dc-bc8a-4bd6-9147-5ea10dfbdb58","gmt_create":"2026-01-29T21:51:04.8388035+08:00","gmt_modified":"2026-01-29T21:51:04.8388035+08:00"},{"id":1767,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"ba0c347382bc5d6fa0bc8ee9ad99ccee","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\http\\index.ts","gmt_create":"2026-02-05T02:04:29.106242+08:00","gmt_modified":"2026-02-05T02:04:29.106242+08:00"},{"id":1768,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"05e7f78e2af29d6f6858eb5c277f9b59","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\store\\rootReducer.ts","gmt_create":"2026-02-05T02:04:29.1067841+08:00","gmt_modified":"2026-02-05T02:04:29.1067841+08:00"},{"id":1769,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"af1b9caae77c3eb18db59f966fa8f159","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\store\\index.ts","gmt_create":"2026-02-05T02:04:29.1073268+08:00","gmt_modified":"2026-02-05T02:04:29.1073268+08:00"},{"id":1770,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"cb988ebff5655773e31df3e5680ecf6d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\type\\User.ts","gmt_create":"2026-02-05T02:04:29.1073268+08:00","gmt_modified":"2026-02-05T02:04:29.1073268+08:00"},{"id":1771,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"f27a9cf496e24f009b20fd0e793eea89","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\type\\Jobs.ts","gmt_create":"2026-02-05T02:04:29.1078725+08:00","gmt_modified":"2026-02-05T02:04:29.1078725+08:00"},{"id":1772,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"a1a5088a35c92c48479526d20f11f3ad","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\type\\dataSource.ts","gmt_create":"2026-02-05T02:04:29.1078725+08:00","gmt_modified":"2026-02-05T02:04:29.1078725+08:00"},{"id":1773,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"409f8b3dc4055b640cbf6c467b7b9a4b","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\utils\\constants.ts","gmt_create":"2026-02-05T02:04:29.1084146+08:00","gmt_modified":"2026-02-05T02:04:29.1084146+08:00"},{"id":1774,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"24846f11ccf9fedec91816ad2003b018","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\Editor\\http\\create.ts","gmt_create":"2026-02-05T02:04:29.1084146+08:00","gmt_modified":"2026-02-05T02:04:29.1084146+08:00"},{"id":1775,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"e5bdf8d3dc23f09104b1078e042a291c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\Editor\\http\\request.interceptor.ts","gmt_create":"2026-02-05T02:04:29.1089645+08:00","gmt_modified":"2026-02-05T02:04:29.1089645+08:00"},{"id":1776,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"11f5e981555687ccd16d77412b20c077","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\Editor\\http\\response.interceptor.ts","gmt_create":"2026-02-05T02:04:29.1095055+08:00","gmt_modified":"2026-02-05T02:04:29.1095055+08:00"},{"id":1777,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"ff1ea9f8e40398a29aa31b9e95423ef9","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\Editor\\locale\\zh_CN.ts","gmt_create":"2026-02-05T02:04:29.1095777+08:00","gmt_modified":"2026-02-05T02:04:29.1095777+08:00"},{"id":1778,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"0a0e77e1c69d35c3d719c936e5de1525","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\Editor\\locale\\en_US.ts","gmt_create":"2026-02-05T02:04:29.1095777+08:00","gmt_modified":"2026-02-05T02:04:29.1095777+08:00"},{"id":1779,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"df78dc6907c45b9ea1f9d747cdc5200a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\locale\\index.tsx","gmt_create":"2026-02-05T02:04:29.1095777+08:00","gmt_modified":"2026-02-05T02:04:29.1095777+08:00"},{"id":1780,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"f6685d6674763c41f90b04d8c155348d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\component\\SwitchLanguage\\index.tsx","gmt_create":"2026-02-05T02:04:29.1095777+08:00","gmt_modified":"2026-02-05T02:04:29.1095777+08:00"},{"id":1781,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"ade9f21f93c88537e28eafc14cf6fdbf","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui\\src\\store\\commonReducer\\index.ts","gmt_create":"2026-02-05T02:04:29.1105343+08:00","gmt_modified":"2026-02-05T02:04:29.1105343+08:00"},{"id":1782,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"9bf43004076c4f684bcd41403a176163","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\http\\index.ts#24-50","gmt_create":"2026-02-05T02:04:29.1105343+08:00","gmt_modified":"2026-02-05T02:04:29.1105343+08:00"},{"id":1783,"source_id":"ba0c347382bc5d6fa0bc8ee9ad99ccee","target_id":"9bf43004076c4f684bcd41403a176163","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 24-50","gmt_create":"2026-02-05T02:04:29.1105343+08:00","gmt_modified":"2026-02-05T02:04:29.1105343+08:00"},{"id":1784,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"6096882f6c5eb65bf0122ffe3c9b1f3b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\Editor\\http\\response.interceptor.ts#1-106","gmt_create":"2026-02-05T02:04:29.1115343+08:00","gmt_modified":"2026-02-05T02:04:29.1115343+08:00"},{"id":1785,"source_id":"11f5e981555687ccd16d77412b20c077","target_id":"6096882f6c5eb65bf0122ffe3c9b1f3b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-106","gmt_create":"2026-02-05T02:04:29.1115343+08:00","gmt_modified":"2026-02-05T02:04:29.1115343+08:00"},{"id":1786,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"2e41a2957effa882695d7e13ae5734f4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\http\\index.ts#9-22","gmt_create":"2026-02-05T02:04:29.1120499+08:00","gmt_modified":"2026-02-05T02:04:29.1120499+08:00"},{"id":1787,"source_id":"ba0c347382bc5d6fa0bc8ee9ad99ccee","target_id":"2e41a2957effa882695d7e13ae5734f4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-22","gmt_create":"2026-02-05T02:04:29.1120499+08:00","gmt_modified":"2026-02-05T02:04:29.1120499+08:00"},{"id":1788,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"112b9005cde5a20dde537db782954868","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\http\\index.ts#39-47","gmt_create":"2026-02-05T02:04:29.1130669+08:00","gmt_modified":"2026-02-05T02:04:29.1130669+08:00"},{"id":1789,"source_id":"ba0c347382bc5d6fa0bc8ee9ad99ccee","target_id":"112b9005cde5a20dde537db782954868","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-47","gmt_create":"2026-02-05T02:04:29.1130669+08:00","gmt_modified":"2026-02-05T02:04:29.1130669+08:00"},{"id":1790,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"1e2d302b8b8dd34e92da513b1bfca148","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\utils\\constants.ts#6","gmt_create":"2026-02-05T02:04:29.1130669+08:00","gmt_modified":"2026-02-05T02:04:29.1130669+08:00"},{"id":1791,"source_id":"409f8b3dc4055b640cbf6c467b7b9a4b","target_id":"1e2d302b8b8dd34e92da513b1bfca148","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6","gmt_create":"2026-02-05T02:04:29.1130669+08:00","gmt_modified":"2026-02-05T02:04:29.1130669+08:00"},{"id":1792,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"76f1f03d035ebabc5917a536653dc49a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\http\\index.ts#9-48","gmt_create":"2026-02-05T02:04:29.1140661+08:00","gmt_modified":"2026-02-05T02:04:29.1140661+08:00"},{"id":1793,"source_id":"ba0c347382bc5d6fa0bc8ee9ad99ccee","target_id":"76f1f03d035ebabc5917a536653dc49a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 9-48","gmt_create":"2026-02-05T02:04:29.1140661+08:00","gmt_modified":"2026-02-05T02:04:29.1140661+08:00"},{"id":1794,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"0c70ad0717f07f161005eb61b3171a54","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\store\\index.ts#12-15","gmt_create":"2026-02-05T02:04:29.1140661+08:00","gmt_modified":"2026-02-05T02:04:29.1140661+08:00"},{"id":1795,"source_id":"af1b9caae77c3eb18db59f966fa8f159","target_id":"0c70ad0717f07f161005eb61b3171a54","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 12-15","gmt_create":"2026-02-05T02:04:29.1140661+08:00","gmt_modified":"2026-02-05T02:04:29.1140661+08:00"},{"id":1796,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"3b9180c665d9df925335a38c94238628","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\store\\rootReducer.ts#6-11","gmt_create":"2026-02-05T02:04:29.1153272+08:00","gmt_modified":"2026-02-05T02:04:29.1153272+08:00"},{"id":1797,"source_id":"05e7f78e2af29d6f6858eb5c277f9b59","target_id":"3b9180c665d9df925335a38c94238628","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 6-11","gmt_create":"2026-02-05T02:04:29.1153272+08:00","gmt_modified":"2026-02-05T02:04:29.1153272+08:00"},{"id":1798,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"9f82b508634e3489911c78cf693800c6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\store\\index.ts#20-23","gmt_create":"2026-02-05T02:04:29.1153272+08:00","gmt_modified":"2026-02-05T02:04:29.1153272+08:00"},{"id":1799,"source_id":"af1b9caae77c3eb18db59f966fa8f159","target_id":"9f82b508634e3489911c78cf693800c6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 20-23","gmt_create":"2026-02-05T02:04:29.1153272+08:00","gmt_modified":"2026-02-05T02:04:29.1153272+08:00"},{"id":1800,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"2f23f438ddbcf34e11b08b9d8b438732","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\store\\commonReducer\\index.ts#41-53","gmt_create":"2026-02-05T02:04:29.1164055+08:00","gmt_modified":"2026-02-05T02:04:29.1164055+08:00"},{"id":1801,"source_id":"ade9f21f93c88537e28eafc14cf6fdbf","target_id":"2f23f438ddbcf34e11b08b9d8b438732","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 41-53","gmt_create":"2026-02-05T02:04:29.1164055+08:00","gmt_modified":"2026-02-05T02:04:29.1164055+08:00"},{"id":1802,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"b0833565150b237c231cb07da13c93e9","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\store\\index.ts#1-26","gmt_create":"2026-02-05T02:04:29.1164055+08:00","gmt_modified":"2026-02-05T02:04:29.1164055+08:00"},{"id":1803,"source_id":"af1b9caae77c3eb18db59f966fa8f159","target_id":"b0833565150b237c231cb07da13c93e9","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-26","gmt_create":"2026-02-05T02:04:29.1164055+08:00","gmt_modified":"2026-02-05T02:04:29.1164055+08:00"},{"id":1804,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"faea7c20546d37fa1c0d4d67b5da2cd4","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\store\\rootReducer.ts#1-26","gmt_create":"2026-02-05T02:04:29.1173964+08:00","gmt_modified":"2026-02-05T02:04:29.1173964+08:00"},{"id":1805,"source_id":"05e7f78e2af29d6f6858eb5c277f9b59","target_id":"faea7c20546d37fa1c0d4d67b5da2cd4","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-26","gmt_create":"2026-02-05T02:04:29.1175886+08:00","gmt_modified":"2026-02-05T02:04:29.1175886+08:00"},{"id":1806,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"cf969e66d861a099a266361fde36337b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\store\\commonReducer\\index.ts#1-73","gmt_create":"2026-02-05T02:04:29.1175886+08:00","gmt_modified":"2026-02-05T02:04:29.1175886+08:00"},{"id":1807,"source_id":"ade9f21f93c88537e28eafc14cf6fdbf","target_id":"cf969e66d861a099a266361fde36337b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-73","gmt_create":"2026-02-05T02:04:29.1186428+08:00","gmt_modified":"2026-02-05T02:04:29.1186428+08:00"},{"id":1808,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"1853a9bfcf63e242ea1c0f605459182a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\type\\User.ts#1-8","gmt_create":"2026-02-05T02:04:29.1186428+08:00","gmt_modified":"2026-02-05T02:04:29.1186428+08:00"},{"id":1809,"source_id":"cb988ebff5655773e31df3e5680ecf6d","target_id":"1853a9bfcf63e242ea1c0f605459182a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-8","gmt_create":"2026-02-05T02:04:29.1186428+08:00","gmt_modified":"2026-02-05T02:04:29.1186428+08:00"},{"id":1810,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"ee09aa347bf39e20805310c59a20bf59","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\type\\Jobs.ts#1-10","gmt_create":"2026-02-05T02:04:29.1186428+08:00","gmt_modified":"2026-02-05T02:04:29.1186428+08:00"},{"id":1811,"source_id":"f27a9cf496e24f009b20fd0e793eea89","target_id":"ee09aa347bf39e20805310c59a20bf59","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-10","gmt_create":"2026-02-05T02:04:29.1196845+08:00","gmt_modified":"2026-02-05T02:04:29.1196845+08:00"},{"id":1812,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"d68efb4c554e2c0cad5636c6461b5ea7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\type\\dataSource.ts#36-50","gmt_create":"2026-02-05T02:04:29.1196845+08:00","gmt_modified":"2026-02-05T02:04:29.1196845+08:00"},{"id":1813,"source_id":"a1a5088a35c92c48479526d20f11f3ad","target_id":"d68efb4c554e2c0cad5636c6461b5ea7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-50","gmt_create":"2026-02-05T02:04:29.1196845+08:00","gmt_modified":"2026-02-05T02:04:29.1196845+08:00"},{"id":1814,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"8206193c6be9e9d0c6d7f4abeef8370e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\type\\dataSource.ts#1-50","gmt_create":"2026-02-05T02:04:29.1196845+08:00","gmt_modified":"2026-02-05T02:04:29.1196845+08:00"},{"id":1815,"source_id":"a1a5088a35c92c48479526d20f11f3ad","target_id":"8206193c6be9e9d0c6d7f4abeef8370e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-50","gmt_create":"2026-02-05T02:04:29.1206912+08:00","gmt_modified":"2026-02-05T02:04:29.1206912+08:00"},{"id":1816,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"d105954b07e16d85a5326375dd11c3b6","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\component\\SwitchLanguage\\index.tsx#1-38","gmt_create":"2026-02-05T02:04:29.1206912+08:00","gmt_modified":"2026-02-05T02:04:29.1206912+08:00"},{"id":1817,"source_id":"f6685d6674763c41f90b04d8c155348d","target_id":"d105954b07e16d85a5326375dd11c3b6","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-38","gmt_create":"2026-02-05T02:04:29.1466554+08:00","gmt_modified":"2026-02-05T02:04:29.1466554+08:00"},{"id":1818,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"79c2e4fc4483c00a3c78c4239cd593f5","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\locale\\index.tsx#32-55","gmt_create":"2026-02-05T02:04:29.1500235+08:00","gmt_modified":"2026-02-05T02:04:29.1500235+08:00"},{"id":1819,"source_id":"df78dc6907c45b9ea1f9d747cdc5200a","target_id":"79c2e4fc4483c00a3c78c4239cd593f5","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-55","gmt_create":"2026-02-05T02:04:29.1505478+08:00","gmt_modified":"2026-02-05T02:04:29.1505478+08:00"},{"id":1820,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"82ab25cb7be7255422c3e7de450cbbe7","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\Editor\\http\\response.interceptor.ts#4-10","gmt_create":"2026-02-05T02:04:29.151072+08:00","gmt_modified":"2026-02-05T02:04:29.151072+08:00"},{"id":1821,"source_id":"11f5e981555687ccd16d77412b20c077","target_id":"82ab25cb7be7255422c3e7de450cbbe7","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 4-10","gmt_create":"2026-02-05T02:04:29.151072+08:00","gmt_modified":"2026-02-05T02:04:29.151072+08:00"},{"id":1822,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"89e0967c031c588772da4cbf53ad94ef","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\Editor\\http\\response.interceptor.ts#42-45","gmt_create":"2026-02-05T02:04:29.151679+08:00","gmt_modified":"2026-02-05T02:04:29.151679+08:00"},{"id":1823,"source_id":"11f5e981555687ccd16d77412b20c077","target_id":"89e0967c031c588772da4cbf53ad94ef","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 42-45","gmt_create":"2026-02-05T02:04:29.151679+08:00","gmt_modified":"2026-02-05T02:04:29.151679+08:00"},{"id":1824,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"3fd956cb1ffa8527dcd23185e5ef12b0","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\Editor\\locale\\zh_CN.ts#1-85","gmt_create":"2026-02-05T02:04:29.1522528+08:00","gmt_modified":"2026-02-05T02:04:29.1522528+08:00"},{"id":1825,"source_id":"ff1ea9f8e40398a29aa31b9e95423ef9","target_id":"3fd956cb1ffa8527dcd23185e5ef12b0","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-85","gmt_create":"2026-02-05T02:04:29.1528706+08:00","gmt_modified":"2026-02-05T02:04:29.1528706+08:00"},{"id":1826,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"b01f4b6de7cd7b3da94c84fa78ac8f9e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\Editor\\locale\\en_US.ts#1-85","gmt_create":"2026-02-05T02:04:29.1528706+08:00","gmt_modified":"2026-02-05T02:04:29.1528706+08:00"},{"id":1827,"source_id":"0a0e77e1c69d35c3d719c936e5de1525","target_id":"b01f4b6de7cd7b3da94c84fa78ac8f9e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-85","gmt_create":"2026-02-05T02:04:29.1533842+08:00","gmt_modified":"2026-02-05T02:04:29.1533842+08:00"},{"id":1828,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"e93fc8c82647c8dbf3029027e58fcc29","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\locale\\index.tsx#1-56","gmt_create":"2026-02-05T02:04:29.1533842+08:00","gmt_modified":"2026-02-05T02:04:29.1533842+08:00"},{"id":1829,"source_id":"df78dc6907c45b9ea1f9d747cdc5200a","target_id":"e93fc8c82647c8dbf3029027e58fcc29","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 1-56","gmt_create":"2026-02-05T02:04:29.1540152+08:00","gmt_modified":"2026-02-05T02:04:29.1540152+08:00"},{"id":1830,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"41de8a8a30bc9e0da8b7f1b51a2b1f7e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\http\\index.ts#39-43","gmt_create":"2026-02-05T02:04:29.1540152+08:00","gmt_modified":"2026-02-05T02:04:29.1540152+08:00"},{"id":1831,"source_id":"ba0c347382bc5d6fa0bc8ee9ad99ccee","target_id":"41de8a8a30bc9e0da8b7f1b51a2b1f7e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 39-43","gmt_create":"2026-02-05T02:04:29.1545273+08:00","gmt_modified":"2026-02-05T02:04:29.1545273+08:00"},{"id":1832,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"d57fd58ee96f8528eada711d6589be84","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\src\\store\\index.ts#7","gmt_create":"2026-02-05T02:04:29.1545273+08:00","gmt_modified":"2026-02-05T02:04:29.1545273+08:00"},{"id":1833,"source_id":"af1b9caae77c3eb18db59f966fa8f159","target_id":"d57fd58ee96f8528eada711d6589be84","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 7","gmt_create":"2026-02-05T02:04:29.1545273+08:00","gmt_modified":"2026-02-05T02:04:29.1545273+08:00"},{"id":1834,"source_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","target_id":"72804749f64d9a0e44f88500848de061","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-ui\\Editor\\http\\response.interceptor.ts#66-105","gmt_create":"2026-02-05T02:04:29.1550688+08:00","gmt_modified":"2026-02-05T02:04:29.1550688+08:00"},{"id":1835,"source_id":"11f5e981555687ccd16d77412b20c077","target_id":"72804749f64d9a0e44f88500848de061","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 66-105","gmt_create":"2026-02-05T02:04:29.1550688+08:00","gmt_modified":"2026-02-05T02:04:29.1550688+08:00"},{"id":1836,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"74c1c18623a5853228e77188e362f6a7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/package.json","gmt_create":"2026-02-05T02:04:47.9859263+08:00","gmt_modified":"2026-02-05T02:04:47.9859263+08:00"},{"id":1837,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"68344cfd42a0ae4acca91b18e4c359eb","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/index.tsx","gmt_create":"2026-02-05T02:04:47.9864413+08:00","gmt_modified":"2026-02-05T02:04:47.9864413+08:00"},{"id":1838,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"35d5278ec083275175c6bf387baf9710","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/App/index.tsx","gmt_create":"2026-02-05T02:04:47.9864413+08:00","gmt_modified":"2026-02-05T02:04:47.9864413+08:00"},{"id":1839,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"46aca3fbc6ab54b2aa3fa33d1d0d4900","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/router/index.tsx","gmt_create":"2026-02-05T02:04:47.9870412+08:00","gmt_modified":"2026-02-05T02:04:47.9870412+08:00"},{"id":1840,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"a4fdc80cad813709cd1c6c7d2d0dec7f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/router/mainRouter.tsx","gmt_create":"2026-02-05T02:04:47.9870412+08:00","gmt_modified":"2026-02-05T02:04:47.9870412+08:00"},{"id":1841,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"399c0a7ab054f2350ed36b41c31ca007","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/store/index.ts","gmt_create":"2026-02-05T02:04:47.9870412+08:00","gmt_modified":"2026-02-05T02:04:47.9870412+08:00"},{"id":1842,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"5b36fa3a2abe725ce56743e681774df5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/store/rootReducer.ts","gmt_create":"2026-02-05T02:04:47.9875443+08:00","gmt_modified":"2026-02-05T02:04:47.9875443+08:00"},{"id":1843,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"42a686cadc9fe1c0a6eed6d375855607","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/store/commonReducer/index.ts","gmt_create":"2026-02-05T02:04:47.9875443+08:00","gmt_modified":"2026-02-05T02:04:47.9875443+08:00"},{"id":1844,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"d7140726fc92b80fa2d20d8175b30402","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/store/userReducer/index.ts","gmt_create":"2026-02-05T02:04:47.9875443+08:00","gmt_modified":"2026-02-05T02:04:47.9875443+08:00"},{"id":1845,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"217592ef23ffabf42fcec603c3b66ac7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/http/index.ts","gmt_create":"2026-02-05T02:04:47.9875443+08:00","gmt_modified":"2026-02-05T02:04:47.9875443+08:00"},{"id":1846,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"dec9131f037c335e81b5e799359e14bf","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/theme/index.tsx","gmt_create":"2026-02-05T02:04:47.9880826+08:00","gmt_modified":"2026-02-05T02:04:47.9880826+08:00"},{"id":1847,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"af6f22d3426cd3443fe1a416f97386d2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/locale/index.tsx","gmt_create":"2026-02-05T02:04:47.9880826+08:00","gmt_modified":"2026-02-05T02:04:47.9880826+08:00"},{"id":1848,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"b21086da745e4737ebdba5f05ecc650c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/locale/zh_CN.ts","gmt_create":"2026-02-05T02:04:47.9880826+08:00","gmt_modified":"2026-02-05T02:04:47.9880826+08:00"},{"id":1849,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"25b27963d08045f84fb9371bba6c2e5d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/locale/en_US.ts","gmt_create":"2026-02-05T02:04:47.9885946+08:00","gmt_modified":"2026-02-05T02:04:47.9885946+08:00"},{"id":1850,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"e2f936ca894a0b966f01ed5ab4b0f1f2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/App/ConfigProvider.tsx","gmt_create":"2026-02-05T02:04:47.9885946+08:00","gmt_modified":"2026-02-05T02:04:47.9885946+08:00"},{"id":1851,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"9924e3d4c1677faeeeaada38da75ef97","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/view/Main/index.tsx","gmt_create":"2026-02-05T02:04:47.9885946+08:00","gmt_modified":"2026-02-05T02:04:47.9885946+08:00"},{"id":1852,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"f746c4af7e8412d553d4d02f9330a768","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/Editor/http/response.interceptor.ts","gmt_create":"2026-02-05T02:04:47.9891064+08:00","gmt_modified":"2026-02-05T02:04:47.9891064+08:00"},{"id":1853,"source_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","target_id":"b1bc69e78b243aecf39295d0c3da3f37","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/src/preset.ts","gmt_create":"2026-02-05T02:04:47.9892261+08:00","gmt_modified":"2026-02-05T02:04:47.9892261+08:00"},{"id":1854,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"0b661879cedb400c9b61d3daf683493f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java","gmt_create":"2026-02-05T02:06:44.8020087+08:00","gmt_modified":"2026-02-05T02:06:44.8020087+08:00"},{"id":1855,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"09f7d92060102828f961c87f881c3712","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java","gmt_create":"2026-02-05T02:06:44.8025087+08:00","gmt_modified":"2026-02-05T02:06:44.8025087+08:00"},{"id":1856,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"37aa79b4682c202fde07bb97de2205ac","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java","gmt_create":"2026-02-05T02:06:44.8025087+08:00","gmt_modified":"2026-02-05T02:06:44.8025087+08:00"},{"id":1857,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"70c29ebe25c4ef8b399ff6d9f0ebdcf5","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java","gmt_create":"2026-02-05T02:06:44.8025087+08:00","gmt_modified":"2026-02-05T02:06:44.8025087+08:00"},{"id":1858,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"3e6b4c47131aa7039fb13a17f2f02186","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java","gmt_create":"2026-02-05T02:06:44.8030083+08:00","gmt_modified":"2026-02-05T02:06:44.8030083+08:00"},{"id":1859,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"e4e9a8401a3a0641202516ad63661495","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java","gmt_create":"2026-02-05T02:06:44.8030083+08:00","gmt_modified":"2026-02-05T02:06:44.8030083+08:00"},{"id":1860,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"4f5ea92a4a8264c5335bf197ccf05741","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ParameterConverter.java","gmt_create":"2026-02-05T02:06:44.8030083+08:00","gmt_modified":"2026-02-05T02:06:44.8030083+08:00"},{"id":1861,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"e5c9cfed0d5b1f12905755197c73a98c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java","gmt_create":"2026-02-05T02:06:44.8035083+08:00","gmt_modified":"2026-02-05T02:06:44.8035083+08:00"},{"id":1862,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"8f7da093fe357a9067ae6fd9a0fbb3c2","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/StatementParser.java","gmt_create":"2026-02-05T02:06:44.8035083+08:00","gmt_modified":"2026-02-05T02:06:44.8035083+08:00"},{"id":1863,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"ab724c47c18fb4a7b224cc113928d8e3","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/StatementSplitter.java","gmt_create":"2026-02-05T02:06:44.8035083+08:00","gmt_modified":"2026-02-05T02:06:44.8035083+08:00"},{"id":1864,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"286fc4f95c427dc86bf0ba1a37c889c4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/MetricScript.java","gmt_create":"2026-02-05T02:06:44.8040259+08:00","gmt_modified":"2026-02-05T02:06:44.8040259+08:00"},{"id":1865,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"74f48d5bbdb82c573a9c3f2391ee88ad","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/TypeConverter.java","gmt_create":"2026-02-05T02:06:44.8040259+08:00","gmt_modified":"2026-02-05T02:06:44.8040259+08:00"},{"id":1866,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"4124b652823469464fe4a1deb45e443e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultList.java","gmt_create":"2026-02-05T02:06:44.8040259+08:00","gmt_modified":"2026-02-05T02:06:44.8040259+08:00"},{"id":1867,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"a579f7a189c2f80f0740d7ebe2924648","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/QueryColumn.java","gmt_create":"2026-02-05T02:06:44.804529+08:00","gmt_modified":"2026-02-05T02:06:44.804529+08:00"},{"id":1868,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"564b5d6f532379703bd0a79fb4e5bbb0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/JdbcUtils.java","gmt_create":"2026-02-05T02:06:44.8050251+08:00","gmt_modified":"2026-02-05T02:06:44.8050251+08:00"},{"id":1869,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"2ff36a79c3faf1cafdc5412531c7c048","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/SqlUtils.java","gmt_create":"2026-02-05T02:06:44.8050251+08:00","gmt_modified":"2026-02-05T02:06:44.8050251+08:00"},{"id":1870,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"263c04b67981521c8a8ce3d521340e7a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java","gmt_create":"2026-02-05T02:06:44.8055246+08:00","gmt_modified":"2026-02-05T02:06:44.8055246+08:00"},{"id":1871,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"ac98266a754db6a4724746a82b445c73","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java","gmt_create":"2026-02-05T02:06:44.8055246+08:00","gmt_modified":"2026-02-05T02:06:44.8055246+08:00"},{"id":1872,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"32bbf4f102dc3571bf9ebf326edbf8f4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java","gmt_create":"2026-02-05T02:06:44.8060244+08:00","gmt_modified":"2026-02-05T02:06:44.8060244+08:00"},{"id":1873,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"73b177f5f46115a651ca21559022e12f","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java","gmt_create":"2026-02-05T02:06:44.8060244+08:00","gmt_modified":"2026-02-05T02:06:44.8060244+08:00"},{"id":1874,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"21c0fbd10a5fb5aa8ea0b7f76769f26d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-maxcompute/src/main/java/io/datavines/connector/plugin/MaxComputeConnector.java","gmt_create":"2026-02-05T02:06:44.8060244+08:00","gmt_modified":"2026-02-05T02:06:44.8060244+08:00"},{"id":1875,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"71bb136541225bb3800ee2ffa170bb30","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-databend/src/main/java/io/datavines/connector/plugin/DatabendConnector.java","gmt_create":"2026-02-05T02:06:44.8065243+08:00","gmt_modified":"2026-02-05T02:06:44.8065243+08:00"},{"id":1876,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"2a888d19dfa6b98f3cd92f53a331460d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java","gmt_create":"2026-02-05T02:06:44.8065243+08:00","gmt_modified":"2026-02-05T02:06:44.8065243+08:00"},{"id":1877,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"98341eb49e7d6021bb0b8f289c3a50e0","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java","gmt_create":"2026-02-05T02:06:44.8070244+08:00","gmt_modified":"2026-02-05T02:06:44.8070244+08:00"},{"id":1878,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"52d5ee8fcb2b9b5abc9d723f6e7186e6","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoConnector.java","gmt_create":"2026-02-05T02:06:44.8070244+08:00","gmt_modified":"2026-02-05T02:06:44.8070244+08:00"},{"id":1879,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"0c6c068910c6fe4d6f40b46ea532fbfb","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java","gmt_create":"2026-02-05T02:06:44.8070244+08:00","gmt_modified":"2026-02-05T02:06:44.8070244+08:00"},{"id":1880,"source_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","target_id":"ec05ee89c35fe6dbb82a753d7b2f2b00","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/api/controller/ErrorDataStorageController.java","gmt_create":"2026-02-05T02:06:44.8075244+08:00","gmt_modified":"2026-02-05T02:06:44.8075244+08:00"},{"id":1881,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"a5a1c1302094a7f0ad499ac5dbcc169d","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java","gmt_create":"2026-02-05T02:06:49.3205005+08:00","gmt_modified":"2026-02-05T02:06:49.3205005+08:00"},{"id":1882,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"95e497ed2833a5a5c0ce2b0c1ecaf595","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java","gmt_create":"2026-02-05T02:06:49.3207608+08:00","gmt_modified":"2026-02-05T02:06:49.3207608+08:00"},{"id":1883,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"0c6c068910c6fe4d6f40b46ea532fbfb","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java","gmt_create":"2026-02-05T02:06:49.3207608+08:00","gmt_modified":"2026-02-05T02:06:49.3207608+08:00"},{"id":1884,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"1454fc7162e0ae8876ddb7143ff96382","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java","gmt_create":"2026-02-05T02:06:49.3207608+08:00","gmt_modified":"2026-02-05T02:06:49.3207608+08:00"},{"id":1885,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"6d78e061d58caa4515d636d642a34c13","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceUpdate.java","gmt_create":"2026-02-05T02:06:49.3212659+08:00","gmt_modified":"2026-02-05T02:06:49.3212659+08:00"},{"id":1886,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"ac98266a754db6a4724746a82b445c73","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java","gmt_create":"2026-02-05T02:06:49.3212659+08:00","gmt_modified":"2026-02-05T02:06:49.3212659+08:00"},{"id":1887,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"cf4ea3c9b721eaada66e59913ad27533","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/param/ConnectorRequestParam.java","gmt_create":"2026-02-05T02:06:49.3217656+08:00","gmt_modified":"2026-02-05T02:06:49.3217656+08:00"},{"id":1888,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"263c04b67981521c8a8ce3d521340e7a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java","gmt_create":"2026-02-05T02:06:49.3217656+08:00","gmt_modified":"2026-02-05T02:06:49.3217656+08:00"},{"id":1889,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"eae1db64e2c712ea75c862736f3f5f29","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java","gmt_create":"2026-02-05T02:06:49.3217656+08:00","gmt_modified":"2026-02-05T02:06:49.3217656+08:00"},{"id":1890,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"3b121017593aad7fa0b67dcc90e93f9a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java","gmt_create":"2026-02-05T02:06:49.3217656+08:00","gmt_modified":"2026-02-05T02:06:49.3217656+08:00"},{"id":1891,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"a705eb537701f770f1223cd88ffa7b94","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/api/dto/vo/DataSourceVO.java","gmt_create":"2026-02-05T02:06:49.3222654+08:00","gmt_modified":"2026-02-05T02:06:49.3222654+08:00"},{"id":1892,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"93586313634147356f53bdd68947b864","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java","gmt_create":"2026-02-05T02:06:49.3222654+08:00","gmt_modified":"2026-02-05T02:06:49.3222654+08:00"},{"id":1893,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"56f7c1356325bc18b6ed13e47d48c411","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/connector-plugins/connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java","gmt_create":"2026-02-05T02:06:49.3227653+08:00","gmt_modified":"2026-02-05T02:06:49.3227653+08:00"},{"id":1894,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"670bcd0b960042739c8d71e706f29e61","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-connector/connector-plugins/connector-oracle/src/main/java/io/datavines/connector/plugin/OracleParameterConverter.java","gmt_create":"2026-02-05T02:06:49.3227653+08:00","gmt_modified":"2026-02-05T02:06:49.3227653+08:00"},{"id":1895,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"b587c1215c65d0ef75f37ebd3d2250af","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java","gmt_create":"2026-02-05T02:06:49.3227653+08:00","gmt_modified":"2026-02-05T02:06:49.3227653+08:00"},{"id":1896,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"fead59530b734a2d6d10d3a8bdf0a471","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#44-167","gmt_create":"2026-02-05T02:06:49.3232654+08:00","gmt_modified":"2026-02-05T02:06:49.3232654+08:00"},{"id":1897,"source_id":"a5a1c1302094a7f0ad499ac5dbcc169d","target_id":"fead59530b734a2d6d10d3a8bdf0a471","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 44-167","gmt_create":"2026-02-05T02:06:49.3232654+08:00","gmt_modified":"2026-02-05T02:06:49.3232654+08:00"},{"id":1898,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"2cbc150b094a14be555fe5982c5234ea","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#56-167","gmt_create":"2026-02-05T02:06:49.3232654+08:00","gmt_modified":"2026-02-05T02:06:49.3232654+08:00"},{"id":1899,"source_id":"a5a1c1302094a7f0ad499ac5dbcc169d","target_id":"2cbc150b094a14be555fe5982c5234ea","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 56-167","gmt_create":"2026-02-05T02:06:49.3237656+08:00","gmt_modified":"2026-02-05T02:06:49.3237656+08:00"},{"id":1900,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"b20b55d193d5fc59c3439d3ca4b2430d","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java#32-51","gmt_create":"2026-02-05T02:06:49.3237656+08:00","gmt_modified":"2026-02-05T02:06:49.3237656+08:00"},{"id":1901,"source_id":"93586313634147356f53bdd68947b864","target_id":"b20b55d193d5fc59c3439d3ca4b2430d","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 32-51","gmt_create":"2026-02-05T02:06:49.3237656+08:00","gmt_modified":"2026-02-05T02:06:49.3237656+08:00"},{"id":1902,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"6bd7929e5a5668930216c58bf96dd67b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/connector-plugins/connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java#36-72","gmt_create":"2026-02-05T02:06:49.3242651+08:00","gmt_modified":"2026-02-05T02:06:49.3242651+08:00"},{"id":1903,"source_id":"56f7c1356325bc18b6ed13e47d48c411","target_id":"6bd7929e5a5668930216c58bf96dd67b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 36-72","gmt_create":"2026-02-05T02:06:49.3242651+08:00","gmt_modified":"2026-02-05T02:06:49.3242651+08:00"},{"id":1904,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"096cd1fb8b55d7adbbf50d3960d8446b","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-connector/connector-plugins/connector-oracle/src/main/java/io/datavines/connector/plugin/OracleParameterConverter.java#25-44","gmt_create":"2026-02-05T02:06:49.3247652+08:00","gmt_modified":"2026-02-05T02:06:49.3247652+08:00"},{"id":1905,"source_id":"670bcd0b960042739c8d71e706f29e61","target_id":"096cd1fb8b55d7adbbf50d3960d8446b","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-44","gmt_create":"2026-02-05T02:06:49.3247652+08:00","gmt_modified":"2026-02-05T02:06:49.3247652+08:00"},{"id":1906,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"85f0fa99dcc801a5e262826c1de187aa","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java#26-39","gmt_create":"2026-02-05T02:06:49.3252651+08:00","gmt_modified":"2026-02-05T02:06:49.3252651+08:00"},{"id":1907,"source_id":"1454fc7162e0ae8876ddb7143ff96382","target_id":"85f0fa99dcc801a5e262826c1de187aa","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-39","gmt_create":"2026-02-05T02:06:49.3252651+08:00","gmt_modified":"2026-02-05T02:06:49.3252651+08:00"},{"id":1908,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"cf33c5c40617d467214ee6588937e66a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-server/src/main/java/io/datavines/server/api/dto/vo/DataSourceVO.java#25-42","gmt_create":"2026-02-05T02:06:49.3257651+08:00","gmt_modified":"2026-02-05T02:06:49.3257651+08:00"},{"id":1909,"source_id":"a705eb537701f770f1223cd88ffa7b94","target_id":"cf33c5c40617d467214ee6588937e66a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 25-42","gmt_create":"2026-02-05T02:06:49.3257651+08:00","gmt_modified":"2026-02-05T02:06:49.3257651+08:00"},{"id":1910,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"1fb4075d646177f68ff77351f534d081","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java#59-86","gmt_create":"2026-02-05T02:06:49.3443602+08:00","gmt_modified":"2026-02-05T02:06:49.3443602+08:00"},{"id":1911,"source_id":"a5a1c1302094a7f0ad499ac5dbcc169d","target_id":"1fb4075d646177f68ff77351f534d081","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 59-86","gmt_create":"2026-02-05T02:06:49.3470375+08:00","gmt_modified":"2026-02-05T02:06:49.3470375+08:00"},{"id":1912,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"5f8e12524eb6a169d5684eb901fc47db","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java#22-25","gmt_create":"2026-02-05T02:06:49.3476514+08:00","gmt_modified":"2026-02-05T02:06:49.3476514+08:00"},{"id":1913,"source_id":"ac98266a754db6a4724746a82b445c73","target_id":"5f8e12524eb6a169d5684eb901fc47db","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-25","gmt_create":"2026-02-05T02:06:49.3476514+08:00","gmt_modified":"2026-02-05T02:06:49.3476514+08:00"},{"id":1914,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"7656d5e22134969f34088283ee21a277","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-common/src/main/java/io/datavines/common/param/ConnectorRequestParam.java#22-27","gmt_create":"2026-02-05T02:06:49.3482262+08:00","gmt_modified":"2026-02-05T02:06:49.3482262+08:00"},{"id":1915,"source_id":"cf4ea3c9b721eaada66e59913ad27533","target_id":"7656d5e22134969f34088283ee21a277","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-27","gmt_create":"2026-02-05T02:06:49.3482262+08:00","gmt_modified":"2026-02-05T02:06:49.3482262+08:00"},{"id":1916,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"79af665211fd45dd3fc2b76e80dbe54f","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java#22-52","gmt_create":"2026-02-05T02:06:49.3482262+08:00","gmt_modified":"2026-02-05T02:06:49.3482262+08:00"},{"id":1917,"source_id":"263c04b67981521c8a8ce3d521340e7a","target_id":"79af665211fd45dd3fc2b76e80dbe54f","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 22-52","gmt_create":"2026-02-05T02:06:49.3487302+08:00","gmt_modified":"2026-02-05T02:06:49.3487302+08:00"},{"id":1918,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"7c2bf2c7c0f153865c5f4168f4eca72e","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java#29-128","gmt_create":"2026-02-05T02:06:49.3487302+08:00","gmt_modified":"2026-02-05T02:06:49.3487302+08:00"},{"id":1919,"source_id":"eae1db64e2c712ea75c862736f3f5f29","target_id":"7c2bf2c7c0f153865c5f4168f4eca72e","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 29-128","gmt_create":"2026-02-05T02:06:49.3493176+08:00","gmt_modified":"2026-02-05T02:06:49.3493176+08:00"},{"id":1920,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"1f8d4de5fb17a98f10ff241f0609a143","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#75-78","gmt_create":"2026-02-05T02:06:49.349633+08:00","gmt_modified":"2026-02-05T02:06:49.349633+08:00"},{"id":1921,"source_id":"0c6c068910c6fe4d6f40b46ea532fbfb","target_id":"1f8d4de5fb17a98f10ff241f0609a143","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 75-78","gmt_create":"2026-02-05T02:06:49.349633+08:00","gmt_modified":"2026-02-05T02:06:49.349633+08:00"},{"id":1922,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"68aeb7cbcb88b7f348067a268be9c509","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java#26-64","gmt_create":"2026-02-05T02:06:49.3499656+08:00","gmt_modified":"2026-02-05T02:06:49.3499656+08:00"},{"id":1923,"source_id":"b587c1215c65d0ef75f37ebd3d2250af","target_id":"68aeb7cbcb88b7f348067a268be9c509","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 26-64","gmt_create":"2026-02-05T02:06:49.3504654+08:00","gmt_modified":"2026-02-05T02:06:49.3504654+08:00"},{"id":1924,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"15d8c34316cb2c4c7b36ed301bb3a0c8","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#150-197","gmt_create":"2026-02-05T02:06:49.3504654+08:00","gmt_modified":"2026-02-05T02:06:49.3504654+08:00"},{"id":1925,"source_id":"0c6c068910c6fe4d6f40b46ea532fbfb","target_id":"15d8c34316cb2c4c7b36ed301bb3a0c8","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 150-197","gmt_create":"2026-02-05T02:06:49.3509656+08:00","gmt_modified":"2026-02-05T02:06:49.3509656+08:00"},{"id":1926,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"3d8e6a2bb3008d205ea5fe594e05c115","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#113-116","gmt_create":"2026-02-05T02:06:49.3509656+08:00","gmt_modified":"2026-02-05T02:06:49.3509656+08:00"},{"id":1927,"source_id":"0c6c068910c6fe4d6f40b46ea532fbfb","target_id":"3d8e6a2bb3008d205ea5fe594e05c115","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 113-116","gmt_create":"2026-02-05T02:06:49.3514656+08:00","gmt_modified":"2026-02-05T02:06:49.3514656+08:00"},{"id":1928,"source_id":"612f25fc-f152-48f9-a992-c650a00573aa","target_id":"e3f35a91be57cc656f6fa5e2323cf88a","source_type":"WIKI_ITEM","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Wiki contains code snippet: datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java#184-189","gmt_create":"2026-02-05T02:06:49.3514656+08:00","gmt_modified":"2026-02-05T02:06:49.3514656+08:00"},{"id":1929,"source_id":"0c6c068910c6fe4d6f40b46ea532fbfb","target_id":"e3f35a91be57cc656f6fa5e2323cf88a","source_type":"SOURCE_FILE","target_type":"CODE_SNIPPET","relationship_type":"CONTAINS","extra":"Source file contains code snippet: 184-189","gmt_create":"2026-02-05T02:06:49.3514656+08:00","gmt_modified":"2026-02-05T02:06:49.3514656+08:00"},{"id":1930,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"165f1bb889ec3e3d4faf22b2526eabe4","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/exception/DataVinesException.java","gmt_create":"2026-02-05T02:06:52.2878503+08:00","gmt_modified":"2026-02-05T02:06:52.2878503+08:00"},{"id":1931,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"b587c1215c65d0ef75f37ebd3d2250af","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java","gmt_create":"2026-02-05T02:06:52.2885109+08:00","gmt_modified":"2026-02-05T02:06:52.2885109+08:00"},{"id":1932,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"f348d62a0e5d91b583b53057dcb9198e","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-core/src/main/java/io/datavines/core/enums/Status.java","gmt_create":"2026-02-05T02:06:52.2885109+08:00","gmt_modified":"2026-02-05T02:06:52.2885109+08:00"},{"id":1933,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"e67fc4501b322e626def8087213aff18","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java","gmt_create":"2026-02-05T02:06:52.2885109+08:00","gmt_modified":"2026-02-05T02:06:52.2885109+08:00"},{"id":1934,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"eae1db64e2c712ea75c862736f3f5f29","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java","gmt_create":"2026-02-05T02:06:52.2890151+08:00","gmt_modified":"2026-02-05T02:06:52.2890151+08:00"},{"id":1935,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"822483f1f6f559028484bb95ec135b33","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java","gmt_create":"2026-02-05T02:06:52.2890151+08:00","gmt_modified":"2026-02-05T02:06:52.2890151+08:00"},{"id":1936,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"bed6a7517ea0bf697e00cd99fb570ff7","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java","gmt_create":"2026-02-05T02:06:52.2890151+08:00","gmt_modified":"2026-02-05T02:06:52.2890151+08:00"},{"id":1937,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"34135d027679e72f52e0341d6d9f9cda","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-core/src/main/java/io/datavines/core/aop/RefreshToken.java","gmt_create":"2026-02-05T02:06:52.2895317+08:00","gmt_modified":"2026-02-05T02:06:52.2895317+08:00"},{"id":1938,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"263c04b67981521c8a8ce3d521340e7a","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java","gmt_create":"2026-02-05T02:06:52.2895317+08:00","gmt_modified":"2026-02-05T02:06:52.2895317+08:00"},{"id":1939,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"7f4168b3fba5fdae8d7f1f6b2815058c","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java","gmt_create":"2026-02-05T02:06:52.2901617+08:00","gmt_modified":"2026-02-05T02:06:52.2901617+08:00"},{"id":1940,"source_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","target_id":"f746c4af7e8412d553d4d02f9330a768","source_type":"WIKI_ITEM","target_type":"SOURCE_FILE","relationship_type":"REFERENCED_BY","extra":"Wiki references source file: datavines-ui/Editor/http/response.interceptor.ts","gmt_create":"2026-02-05T02:06:52.290483+08:00","gmt_modified":"2026-02-05T02:06:52.290483+08:00"},{"id":1941,"source_id":"a8bc817f-96f5-400b-a9c9-8cd17a45753e","target_id":"612f25fc-f152-48f9-a992-c650a00573aa","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: a8bc817f-96f5-400b-a9c9-8cd17a45753e -\u003e 612f25fc-f152-48f9-a992-c650a00573aa","gmt_create":"2026-02-05T02:06:52.3831193+08:00","gmt_modified":"2026-02-05T02:06:52.3831193+08:00"},{"id":1942,"source_id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","target_id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 93eeddb1-5a4a-4bf3-a0ff-966d57beb5da -\u003e 3d9127ca-86f1-446d-bc7b-cf696f6c2a00","gmt_create":"2026-02-05T02:06:52.3878623+08:00","gmt_modified":"2026-02-05T02:06:52.3878623+08:00"},{"id":1943,"source_id":"4568681a-4970-4d2f-86cc-330effb87a9d","target_id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4568681a-4970-4d2f-86cc-330effb87a9d -\u003e 803a3ec5-5bc3-480b-9987-da3193f9f6db","gmt_create":"2026-02-05T02:06:52.3909887+08:00","gmt_modified":"2026-02-05T02:06:52.3909887+08:00"},{"id":1944,"source_id":"4568681a-4970-4d2f-86cc-330effb87a9d","target_id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4568681a-4970-4d2f-86cc-330effb87a9d -\u003e f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","gmt_create":"2026-02-05T02:06:52.3915047+08:00","gmt_modified":"2026-02-05T02:06:52.3915047+08:00"},{"id":1945,"source_id":"18ad9731-a15d-4bf0-9c19-de571e4b9a87","target_id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 18ad9731-a15d-4bf0-9c19-de571e4b9a87 -\u003e 0a55bfbc-e3af-4c06-b845-7faa5c899111","gmt_create":"2026-02-05T02:06:52.4041189+08:00","gmt_modified":"2026-02-05T02:06:52.4041189+08:00"}],"source_files":[{"id":"0b661879cedb400c9b61d3daf683493f","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java","filename":"Connector.java","gmt_create":"2026-01-29T21:48:29.2923789+08:00","gmt_modified":"2026-01-29T21:48:29.2923789+08:00"},{"id":"37aa79b4682c202fde07bb97de2205ac","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java","filename":"Dialect.java","gmt_create":"2026-01-29T21:48:29.292888+08:00","gmt_modified":"2026-01-29T21:48:29.292888+08:00"},{"id":"09f7d92060102828f961c87f881c3712","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java","filename":"DataSourceClient.java","gmt_create":"2026-01-29T21:48:29.292888+08:00","gmt_modified":"2026-01-29T21:48:29.292888+08:00"},{"id":"70c29ebe25c4ef8b399ff6d9f0ebdcf5","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java","filename":"Executor.java","gmt_create":"2026-01-29T21:48:29.292888+08:00","gmt_modified":"2026-01-29T21:48:29.292888+08:00"},{"id":"4e4727c0aacc3d9cc347c9917c686126","path":"datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java","filename":"JdbcDataSourceManager.java","gmt_create":"2026-01-29T21:48:29.2933465+08:00","gmt_modified":"2026-01-29T21:48:29.2933465+08:00"},{"id":"32bbf4f102dc3571bf9ebf326edbf8f4","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java","filename":"JdbcConnector.java","gmt_create":"2026-01-29T21:48:29.2933465+08:00","gmt_modified":"2026-01-29T21:48:29.2933465+08:00"},{"id":"8b3157caf21880d8b0e7d859e41314d7","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java","filename":"JdbcDialect.java","gmt_create":"2026-01-29T21:48:29.2933465+08:00","gmt_modified":"2026-01-29T21:48:29.2933465+08:00"},{"id":"13fd44fc6163676f8ebee5cc92f99bb0","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/BaseJdbcExecutor.java","filename":"BaseJdbcExecutor.java","gmt_create":"2026-01-29T21:48:29.2933465+08:00","gmt_modified":"2026-01-29T21:48:29.2933465+08:00"},{"id":"a2a3409cda4dd26ceacaa4179b8f539a","path":"datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcConnectionInfo.java","filename":"JdbcConnectionInfo.java","gmt_create":"2026-01-29T21:48:29.2933465+08:00","gmt_modified":"2026-01-29T21:48:29.2933465+08:00"},{"id":"3fdd1b1df830bf6cf2c3ca092dd6a111","path":"datavines-common/src/main/java/io/datavines/common/datasource/jdbc/BaseJdbcDataSourceInfo.java","filename":"BaseJdbcDataSourceInfo.java","gmt_create":"2026-01-29T21:48:29.2938483+08:00","gmt_modified":"2026-01-29T21:48:29.2938483+08:00"},{"id":"6be402d159c79d233b2f9021df5ace47","path":"datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java","filename":"MysqlConnector.java","gmt_create":"2026-01-29T21:48:29.2938483+08:00","gmt_modified":"2026-01-29T21:48:29.2938483+08:00"},{"id":"7a80cd0418c6ade29f7450ba58bd7eae","path":"datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java","filename":"PostgreSqlConnector.java","gmt_create":"2026-01-29T21:48:29.2938483+08:00","gmt_modified":"2026-01-29T21:48:29.2938483+08:00"},{"id":"2a888d19dfa6b98f3cd92f53a331460d","path":"datavines-connector/datavines-connector-plugins/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java","filename":"HiveConnector.java","gmt_create":"2026-01-29T21:48:29.2938483+08:00","gmt_modified":"2026-01-29T21:48:29.2938483+08:00"},{"id":"3c383b66697430c3aabded26176c698a","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java","filename":"DorisConnector.java","gmt_create":"2026-01-29T21:48:29.2943468+08:00","gmt_modified":"2026-01-29T21:48:29.2943468+08:00"},{"id":"1525e304646696f9e56b733b2ee0f7d9","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java","filename":"DorisDataSourceInfo.java","gmt_create":"2026-01-29T21:48:29.2943468+08:00","gmt_modified":"2026-01-29T21:48:29.2943468+08:00"},{"id":"b47d0a2071e708e116371678d9b4b6f8","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisParameterConverter.java","filename":"DorisParameterConverter.java","gmt_create":"2026-01-29T21:48:29.2943468+08:00","gmt_modified":"2026-01-29T21:48:29.2943468+08:00"},{"id":"f724dc8d352d041d1310a330bf104c58","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConfigBuilder.java","filename":"DorisConfigBuilder.java","gmt_create":"2026-01-29T21:48:29.2943468+08:00","gmt_modified":"2026-01-29T21:48:29.2943468+08:00"},{"id":"ba0301372f1e73a6524ba558633ce3d7","path":"datavines-common/src/main/java/io/datavines/common/ConfigConstants.java","filename":"ConfigConstants.java","gmt_create":"2026-01-29T21:48:29.2949005+08:00","gmt_modified":"2026-01-29T21:48:29.2949005+08:00"},{"id":"e4e9a8401a3a0641202516ad63661495","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConfigBuilder.java","filename":"ConfigBuilder.java","gmt_create":"2026-01-29T21:49:21.8898648+08:00","gmt_modified":"2026-01-29T21:49:21.8898648+08:00"},{"id":"98d07543ade7080eb0286f7e45dfc334","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java","filename":"JdbcDataSourceClient.java","gmt_create":"2026-01-29T21:49:21.8903897+08:00","gmt_modified":"2026-01-29T21:49:21.8903897+08:00"},{"id":"fb8253d4c7d179918b6aca3e77ad9933","path":"datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java","filename":"JdbcConfigBuilder.java","gmt_create":"2026-01-29T21:49:21.8908654+08:00","gmt_modified":"2026-01-29T21:49:21.8908654+08:00"},{"id":"1114b0c39352aeb37b7098e8dc051054","path":"datavines-connector/datavines-connector-plugins/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java","filename":"OracleConnector.java","gmt_create":"2026-01-29T21:49:21.8913338+08:00","gmt_modified":"2026-01-29T21:49:21.8913338+08:00"},{"id":"392a5a4399de01ca2207faad3b87fd67","path":"datavines-connector/datavines-connector-plugins/datavines-connector-clickhouse/src/main/java/io/datavines/connector/plugin/ClickHouseConnector.java","filename":"ClickHouseConnector.java","gmt_create":"2026-01-29T21:49:21.8913338+08:00","gmt_modified":"2026-01-29T21:49:21.8913338+08:00"},{"id":"4b6b7ea4410be6c0507bed82ae92cf67","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDialect.java","filename":"DorisDialect.java","gmt_create":"2026-01-29T21:49:21.8918338+08:00","gmt_modified":"2026-01-29T21:49:21.8918338+08:00"},{"id":"bdd667272cc3195e320af49a3cec6735","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisExecutor.java","filename":"DorisExecutor.java","gmt_create":"2026-01-29T21:49:21.8923337+08:00","gmt_modified":"2026-01-29T21:49:21.8923337+08:00"},{"id":"fcf6660d99d891324d3466506759f9ee","path":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java","filename":"DorisConnectorFactory.java","gmt_create":"2026-01-29T21:49:21.8923337+08:00","gmt_modified":"2026-01-29T21:49:21.8923337+08:00"},{"id":"ba0c347382bc5d6fa0bc8ee9ad99ccee","path":"datavines-ui\\src\\http\\index.ts","filename":"index.ts","gmt_create":"2026-02-05T02:04:29.0990339+08:00","gmt_modified":"2026-02-05T02:04:29.0990339+08:00"},{"id":"05e7f78e2af29d6f6858eb5c277f9b59","path":"datavines-ui\\src\\store\\rootReducer.ts","filename":"rootReducer.ts","gmt_create":"2026-02-05T02:04:29.0995732+08:00","gmt_modified":"2026-02-05T02:04:29.0995732+08:00"},{"id":"af1b9caae77c3eb18db59f966fa8f159","path":"datavines-ui\\src\\store\\index.ts","filename":"index.ts","gmt_create":"2026-02-05T02:04:29.0995732+08:00","gmt_modified":"2026-02-05T02:04:29.0995732+08:00"},{"id":"cb988ebff5655773e31df3e5680ecf6d","path":"datavines-ui\\src\\type\\User.ts","filename":"User.ts","gmt_create":"2026-02-05T02:04:29.0995732+08:00","gmt_modified":"2026-02-05T02:04:29.0995732+08:00"},{"id":"f27a9cf496e24f009b20fd0e793eea89","path":"datavines-ui\\src\\type\\Jobs.ts","filename":"Jobs.ts","gmt_create":"2026-02-05T02:04:29.0995732+08:00","gmt_modified":"2026-02-05T02:04:29.0995732+08:00"},{"id":"a1a5088a35c92c48479526d20f11f3ad","path":"datavines-ui\\src\\type\\dataSource.ts","filename":"dataSource.ts","gmt_create":"2026-02-05T02:04:29.1001166+08:00","gmt_modified":"2026-02-05T02:04:29.1001166+08:00"},{"id":"409f8b3dc4055b640cbf6c467b7b9a4b","path":"datavines-ui\\src\\utils\\constants.ts","filename":"constants.ts","gmt_create":"2026-02-05T02:04:29.1001166+08:00","gmt_modified":"2026-02-05T02:04:29.1001166+08:00"},{"id":"24846f11ccf9fedec91816ad2003b018","path":"datavines-ui\\Editor\\http\\create.ts","filename":"create.ts","gmt_create":"2026-02-05T02:04:29.1001166+08:00","gmt_modified":"2026-02-05T02:04:29.1001166+08:00"},{"id":"e5bdf8d3dc23f09104b1078e042a291c","path":"datavines-ui\\Editor\\http\\request.interceptor.ts","filename":"request.interceptor.ts","gmt_create":"2026-02-05T02:04:29.1001166+08:00","gmt_modified":"2026-02-05T02:04:29.1001166+08:00"},{"id":"11f5e981555687ccd16d77412b20c077","path":"datavines-ui\\Editor\\http\\response.interceptor.ts","filename":"response.interceptor.ts","gmt_create":"2026-02-05T02:04:29.1001166+08:00","gmt_modified":"2026-02-05T02:04:29.1001166+08:00"},{"id":"ff1ea9f8e40398a29aa31b9e95423ef9","path":"datavines-ui\\Editor\\locale\\zh_CN.ts","filename":"zh_CN.ts","gmt_create":"2026-02-05T02:04:29.1001166+08:00","gmt_modified":"2026-02-05T02:04:29.1001166+08:00"},{"id":"0a0e77e1c69d35c3d719c936e5de1525","path":"datavines-ui\\Editor\\locale\\en_US.ts","filename":"en_US.ts","gmt_create":"2026-02-05T02:04:29.1001166+08:00","gmt_modified":"2026-02-05T02:04:29.1001166+08:00"},{"id":"df78dc6907c45b9ea1f9d747cdc5200a","path":"datavines-ui\\src\\locale\\index.tsx","filename":"index.tsx","gmt_create":"2026-02-05T02:04:29.1006489+08:00","gmt_modified":"2026-02-05T02:04:29.1006489+08:00"},{"id":"f6685d6674763c41f90b04d8c155348d","path":"datavines-ui\\src\\component\\SwitchLanguage\\index.tsx","filename":"index.tsx","gmt_create":"2026-02-05T02:04:29.1006489+08:00","gmt_modified":"2026-02-05T02:04:29.1006489+08:00"},{"id":"ade9f21f93c88537e28eafc14cf6fdbf","path":"datavines-ui\\src\\store\\commonReducer\\index.ts","filename":"index.ts","gmt_create":"2026-02-05T02:04:29.1006489+08:00","gmt_modified":"2026-02-05T02:04:29.1006489+08:00"},{"id":"74c1c18623a5853228e77188e362f6a7","path":"datavines-ui/package.json","filename":"package.json","gmt_create":"2026-02-05T02:04:47.9847141+08:00","gmt_modified":"2026-02-05T02:04:47.9847141+08:00"},{"id":"68344cfd42a0ae4acca91b18e4c359eb","path":"datavines-ui/src/index.tsx","filename":"index.tsx","gmt_create":"2026-02-05T02:04:47.9847141+08:00","gmt_modified":"2026-02-05T02:04:47.9847141+08:00"},{"id":"35d5278ec083275175c6bf387baf9710","path":"datavines-ui/src/App/index.tsx","filename":"index.tsx","gmt_create":"2026-02-05T02:04:47.9847141+08:00","gmt_modified":"2026-02-05T02:04:47.9847141+08:00"},{"id":"46aca3fbc6ab54b2aa3fa33d1d0d4900","path":"datavines-ui/src/router/index.tsx","filename":"index.tsx","gmt_create":"2026-02-05T02:04:47.9847141+08:00","gmt_modified":"2026-02-05T02:04:47.9847141+08:00"},{"id":"a4fdc80cad813709cd1c6c7d2d0dec7f","path":"datavines-ui/src/router/mainRouter.tsx","filename":"mainRouter.tsx","gmt_create":"2026-02-05T02:04:47.9852486+08:00","gmt_modified":"2026-02-05T02:04:47.9852486+08:00"},{"id":"399c0a7ab054f2350ed36b41c31ca007","path":"datavines-ui/src/store/index.ts","filename":"index.ts","gmt_create":"2026-02-05T02:04:47.9852993+08:00","gmt_modified":"2026-02-05T02:04:47.9852993+08:00"},{"id":"5b36fa3a2abe725ce56743e681774df5","path":"datavines-ui/src/store/rootReducer.ts","filename":"rootReducer.ts","gmt_create":"2026-02-05T02:04:47.9854217+08:00","gmt_modified":"2026-02-05T02:04:47.9854217+08:00"},{"id":"42a686cadc9fe1c0a6eed6d375855607","path":"datavines-ui/src/store/commonReducer/index.ts","filename":"index.ts","gmt_create":"2026-02-05T02:04:47.9854217+08:00","gmt_modified":"2026-02-05T02:04:47.9854217+08:00"},{"id":"d7140726fc92b80fa2d20d8175b30402","path":"datavines-ui/src/store/userReducer/index.ts","filename":"index.ts","gmt_create":"2026-02-05T02:04:47.9854217+08:00","gmt_modified":"2026-02-05T02:04:47.9854217+08:00"},{"id":"217592ef23ffabf42fcec603c3b66ac7","path":"datavines-ui/src/http/index.ts","filename":"index.ts","gmt_create":"2026-02-05T02:04:47.9854217+08:00","gmt_modified":"2026-02-05T02:04:47.9854217+08:00"},{"id":"dec9131f037c335e81b5e799359e14bf","path":"datavines-ui/src/theme/index.tsx","filename":"index.tsx","gmt_create":"2026-02-05T02:04:47.9854217+08:00","gmt_modified":"2026-02-05T02:04:47.9854217+08:00"},{"id":"af6f22d3426cd3443fe1a416f97386d2","path":"datavines-ui/src/locale/index.tsx","filename":"index.tsx","gmt_create":"2026-02-05T02:04:47.9854217+08:00","gmt_modified":"2026-02-05T02:04:47.9854217+08:00"},{"id":"b21086da745e4737ebdba5f05ecc650c","path":"datavines-ui/src/locale/zh_CN.ts","filename":"zh_CN.ts","gmt_create":"2026-02-05T02:04:47.9854217+08:00","gmt_modified":"2026-02-05T02:04:47.9854217+08:00"},{"id":"25b27963d08045f84fb9371bba6c2e5d","path":"datavines-ui/src/locale/en_US.ts","filename":"en_US.ts","gmt_create":"2026-02-05T02:04:47.9854217+08:00","gmt_modified":"2026-02-05T02:04:47.9854217+08:00"},{"id":"e2f936ca894a0b966f01ed5ab4b0f1f2","path":"datavines-ui/src/App/ConfigProvider.tsx","filename":"ConfigProvider.tsx","gmt_create":"2026-02-05T02:04:47.9859263+08:00","gmt_modified":"2026-02-05T02:04:47.9859263+08:00"},{"id":"9924e3d4c1677faeeeaada38da75ef97","path":"datavines-ui/src/view/Main/index.tsx","filename":"index.tsx","gmt_create":"2026-02-05T02:04:47.9859263+08:00","gmt_modified":"2026-02-05T02:04:47.9859263+08:00"},{"id":"f746c4af7e8412d553d4d02f9330a768","path":"datavines-ui/Editor/http/response.interceptor.ts","filename":"response.interceptor.ts","gmt_create":"2026-02-05T02:04:47.9859263+08:00","gmt_modified":"2026-02-05T02:04:47.9859263+08:00"},{"id":"b1bc69e78b243aecf39295d0c3da3f37","path":"datavines-ui/src/preset.ts","filename":"preset.ts","gmt_create":"2026-02-05T02:04:47.9859263+08:00","gmt_modified":"2026-02-05T02:04:47.9859263+08:00"},{"id":"3e6b4c47131aa7039fb13a17f2f02186","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java","filename":"ConnectorFactory.java","gmt_create":"2026-02-05T02:06:44.8005087+08:00","gmt_modified":"2026-02-05T02:06:44.8005087+08:00"},{"id":"4f5ea92a4a8264c5335bf197ccf05741","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ParameterConverter.java","filename":"ParameterConverter.java","gmt_create":"2026-02-05T02:06:44.8005087+08:00","gmt_modified":"2026-02-05T02:06:44.8005087+08:00"},{"id":"e5c9cfed0d5b1f12905755197c73a98c","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java","filename":"ResponseConverter.java","gmt_create":"2026-02-05T02:06:44.8005087+08:00","gmt_modified":"2026-02-05T02:06:44.8005087+08:00"},{"id":"8f7da093fe357a9067ae6fd9a0fbb3c2","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/StatementParser.java","filename":"StatementParser.java","gmt_create":"2026-02-05T02:06:44.8010085+08:00","gmt_modified":"2026-02-05T02:06:44.8010085+08:00"},{"id":"ab724c47c18fb4a7b224cc113928d8e3","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/StatementSplitter.java","filename":"StatementSplitter.java","gmt_create":"2026-02-05T02:06:44.8010085+08:00","gmt_modified":"2026-02-05T02:06:44.8010085+08:00"},{"id":"286fc4f95c427dc86bf0ba1a37c889c4","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/MetricScript.java","filename":"MetricScript.java","gmt_create":"2026-02-05T02:06:44.8010085+08:00","gmt_modified":"2026-02-05T02:06:44.8010085+08:00"},{"id":"74f48d5bbdb82c573a9c3f2391ee88ad","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/TypeConverter.java","filename":"TypeConverter.java","gmt_create":"2026-02-05T02:06:44.8010085+08:00","gmt_modified":"2026-02-05T02:06:44.8010085+08:00"},{"id":"4124b652823469464fe4a1deb45e443e","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/ResultList.java","filename":"ResultList.java","gmt_create":"2026-02-05T02:06:44.8010085+08:00","gmt_modified":"2026-02-05T02:06:44.8010085+08:00"},{"id":"a579f7a189c2f80f0740d7ebe2924648","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/entity/QueryColumn.java","filename":"QueryColumn.java","gmt_create":"2026-02-05T02:06:44.8010085+08:00","gmt_modified":"2026-02-05T02:06:44.8010085+08:00"},{"id":"564b5d6f532379703bd0a79fb4e5bbb0","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/JdbcUtils.java","filename":"JdbcUtils.java","gmt_create":"2026-02-05T02:06:44.8010085+08:00","gmt_modified":"2026-02-05T02:06:44.8010085+08:00"},{"id":"2ff36a79c3faf1cafdc5412531c7c048","path":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/utils/SqlUtils.java","filename":"SqlUtils.java","gmt_create":"2026-02-05T02:06:44.8010085+08:00","gmt_modified":"2026-02-05T02:06:44.8010085+08:00"},{"id":"263c04b67981521c8a8ce3d521340e7a","path":"datavines-common/src/main/java/io/datavines/common/param/ConnectorResponse.java","filename":"ConnectorResponse.java","gmt_create":"2026-02-05T02:06:44.8015082+08:00","gmt_modified":"2026-02-05T02:06:44.8015082+08:00"},{"id":"ac98266a754db6a4724746a82b445c73","path":"datavines-common/src/main/java/io/datavines/common/param/TestConnectionRequestParam.java","filename":"TestConnectionRequestParam.java","gmt_create":"2026-02-05T02:06:44.8015082+08:00","gmt_modified":"2026-02-05T02:06:44.8015082+08:00"},{"id":"73b177f5f46115a651ca21559022e12f","path":"datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java","filename":"MongodbConnector.java","gmt_create":"2026-02-05T02:06:44.8015082+08:00","gmt_modified":"2026-02-05T02:06:44.8015082+08:00"},{"id":"21c0fbd10a5fb5aa8ea0b7f76769f26d","path":"datavines-connector/datavines-connector-plugins/datavines-connector-maxcompute/src/main/java/io/datavines/connector/plugin/MaxComputeConnector.java","filename":"MaxComputeConnector.java","gmt_create":"2026-02-05T02:06:44.8015082+08:00","gmt_modified":"2026-02-05T02:06:44.8015082+08:00"},{"id":"71bb136541225bb3800ee2ffa170bb30","path":"datavines-connector/datavines-connector-plugins/datavines-connector-databend/src/main/java/io/datavines/connector/plugin/DatabendConnector.java","filename":"DatabendConnector.java","gmt_create":"2026-02-05T02:06:44.8015082+08:00","gmt_modified":"2026-02-05T02:06:44.8015082+08:00"},{"id":"98341eb49e7d6021bb0b8f289c3a50e0","path":"datavines-connector/datavines-connector-plugins/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java","filename":"PrestoConnector.java","gmt_create":"2026-02-05T02:06:44.8015082+08:00","gmt_modified":"2026-02-05T02:06:44.8015082+08:00"},{"id":"52d5ee8fcb2b9b5abc9d723f6e7186e6","path":"datavines-connector/datavines-connector-plugins/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoConnector.java","filename":"TrinoConnector.java","gmt_create":"2026-02-05T02:06:44.8020087+08:00","gmt_modified":"2026-02-05T02:06:44.8020087+08:00"},{"id":"0c6c068910c6fe4d6f40b46ea532fbfb","path":"datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java","filename":"DataSourceServiceImpl.java","gmt_create":"2026-02-05T02:06:44.8020087+08:00","gmt_modified":"2026-02-05T02:06:44.8020087+08:00"},{"id":"ec05ee89c35fe6dbb82a753d7b2f2b00","path":"datavines-server/src/main/java/io/datavines/server/api/controller/ErrorDataStorageController.java","filename":"ErrorDataStorageController.java","gmt_create":"2026-02-05T02:06:44.8020087+08:00","gmt_modified":"2026-02-05T02:06:44.8020087+08:00"},{"id":"a5a1c1302094a7f0ad499ac5dbcc169d","path":"datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java","filename":"DataSourceController.java","gmt_create":"2026-02-05T02:06:49.3165076+08:00","gmt_modified":"2026-02-05T02:06:49.3165076+08:00"},{"id":"95e497ed2833a5a5c0ce2b0c1ecaf595","path":"datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java","filename":"DataSourceService.java","gmt_create":"2026-02-05T02:06:49.3165076+08:00","gmt_modified":"2026-02-05T02:06:49.3165076+08:00"},{"id":"1454fc7162e0ae8876ddb7143ff96382","path":"datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java","filename":"DataSourceCreate.java","gmt_create":"2026-02-05T02:06:49.3170267+08:00","gmt_modified":"2026-02-05T02:06:49.3170267+08:00"},{"id":"6d78e061d58caa4515d636d642a34c13","path":"datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceUpdate.java","filename":"DataSourceUpdate.java","gmt_create":"2026-02-05T02:06:49.3170267+08:00","gmt_modified":"2026-02-05T02:06:49.3170267+08:00"},{"id":"cf4ea3c9b721eaada66e59913ad27533","path":"datavines-common/src/main/java/io/datavines/common/param/ConnectorRequestParam.java","filename":"ConnectorRequestParam.java","gmt_create":"2026-02-05T02:06:49.3170267+08:00","gmt_modified":"2026-02-05T02:06:49.3170267+08:00"},{"id":"eae1db64e2c712ea75c862736f3f5f29","path":"datavines-core/src/main/java/io/datavines/core/entity/ResultMap.java","filename":"ResultMap.java","gmt_create":"2026-02-05T02:06:49.3170267+08:00","gmt_modified":"2026-02-05T02:06:49.3170267+08:00"},{"id":"3b121017593aad7fa0b67dcc90e93f9a","path":"datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java","filename":"DataSource.java","gmt_create":"2026-02-05T02:06:49.3175431+08:00","gmt_modified":"2026-02-05T02:06:49.3175431+08:00"},{"id":"a705eb537701f770f1223cd88ffa7b94","path":"datavines-server/src/main/java/io/datavines/server/api/dto/vo/DataSourceVO.java","filename":"DataSourceVO.java","gmt_create":"2026-02-05T02:06:49.3176749+08:00","gmt_modified":"2026-02-05T02:06:49.3176749+08:00"},{"id":"93586313634147356f53bdd68947b864","path":"datavines-common/src/main/java/io/datavines/common/entity/ConnectionInfo.java","filename":"ConnectionInfo.java","gmt_create":"2026-02-05T02:06:49.3176749+08:00","gmt_modified":"2026-02-05T02:06:49.3176749+08:00"},{"id":"56f7c1356325bc18b6ed13e47d48c411","path":"datavines-connector/connector-plugins/connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConfigBuilder.java","filename":"JdbcConfigBuilder.java","gmt_create":"2026-02-05T02:06:49.3176749+08:00","gmt_modified":"2026-02-05T02:06:49.3176749+08:00"},{"id":"670bcd0b960042739c8d71e706f29e61","path":"datavines-connector/connector-plugins/connector-oracle/src/main/java/io/datavines/connector/plugin/OracleParameterConverter.java","filename":"OracleParameterConverter.java","gmt_create":"2026-02-05T02:06:49.3176749+08:00","gmt_modified":"2026-02-05T02:06:49.3176749+08:00"},{"id":"b587c1215c65d0ef75f37ebd3d2250af","path":"datavines-core/src/main/java/io/datavines/core/exception/DataVinesServerException.java","filename":"DataVinesServerException.java","gmt_create":"2026-02-05T02:06:49.3176749+08:00","gmt_modified":"2026-02-05T02:06:49.3176749+08:00"},{"id":"165f1bb889ec3e3d4faf22b2526eabe4","path":"datavines-common/src/main/java/io/datavines/common/exception/DataVinesException.java","filename":"DataVinesException.java","gmt_create":"2026-02-05T02:06:52.2872919+08:00","gmt_modified":"2026-02-05T02:06:52.2872919+08:00"},{"id":"f348d62a0e5d91b583b53057dcb9198e","path":"datavines-core/src/main/java/io/datavines/core/enums/Status.java","filename":"Status.java","gmt_create":"2026-02-05T02:06:52.2873454+08:00","gmt_modified":"2026-02-05T02:06:52.2873454+08:00"},{"id":"e67fc4501b322e626def8087213aff18","path":"datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java","filename":"DataVinesExceptionHandler.java","gmt_create":"2026-02-05T02:06:52.2873454+08:00","gmt_modified":"2026-02-05T02:06:52.2873454+08:00"},{"id":"822483f1f6f559028484bb95ec135b33","path":"datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java","filename":"TokenManager.java","gmt_create":"2026-02-05T02:06:52.2878503+08:00","gmt_modified":"2026-02-05T02:06:52.2878503+08:00"},{"id":"bed6a7517ea0bf697e00cd99fb570ff7","path":"datavines-core/src/main/java/io/datavines/core/aop/RefreshTokenAop.java","filename":"RefreshTokenAop.java","gmt_create":"2026-02-05T02:06:52.2878503+08:00","gmt_modified":"2026-02-05T02:06:52.2878503+08:00"},{"id":"34135d027679e72f52e0341d6d9f9cda","path":"datavines-core/src/main/java/io/datavines/core/aop/RefreshToken.java","filename":"RefreshToken.java","gmt_create":"2026-02-05T02:06:52.2878503+08:00","gmt_modified":"2026-02-05T02:06:52.2878503+08:00"},{"id":"7f4168b3fba5fdae8d7f1f6b2815058c","path":"datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java","filename":"TimeoutStrategy.java","gmt_create":"2026-02-05T02:06:52.2878503+08:00","gmt_modified":"2026-02-05T02:06:52.2878503+08:00"}],"wiki_catalogs":[{"id":"4b2293e2-2fb0-4953-90ce-d1ca86762e3b","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"项目概述","description":"project-overview","prompt":"创建全面的项目概述内容,重点介绍DataVines平台。解释其作为数据质量服务化平台的目的、核心功能和整体架构。涵盖数据目录、数据质量检查、数据画像等主要特性。描述系统的技术栈,包括Spring Boot后端、React前端以及对Spark、Flink等计算引擎的支持。说明微内核架构和SPI插件机制的设计理念。提供项目背景、设计目标和适用场景的详细说明。包含与其他数据质量管理工具的对比分析,突出DataVines的独特优势。为初学者提供概念性概述,同时为经验丰富的开发者提供足够的技术深度。","progress_status":"completed","dependent_files":"README.md,README.zh-CN.md,pom.xml","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-25T23:49:38+08:00","raw_data":"WikiEncrypted:0MI1/XkBoMl0lTbK6t0Cn/+8FdvqrJ62ianMLvZj02elJtBUgH0Ns0veIx1WPtM9wwkxI+/XAqHLxJLlHB8wV7ojrH0+b4JMz5OewwhBN1EYle5jZChpdEm39BNNPXG1bpFxdxvxcwiRQWIrhYpUUx0gW3mFPpGabqzxZaKtrOXFD/6MWNOZk82Y8AJXQOpeeodeUaeLoXA+3CwZS0fftfJvtubAxGy8fLoNteWvBf28BIK5Zj+NEkQE02xHEirIGQDzARo8nFZ+bSo+GoZjMt40Qdk+Ed5TTkFYnst/ATq3PnRYhOa7DddG3tfgrXEid73Z7DBintNs35rDjOSYjpv0kpIcuLpCB/GaDALceZDExmmLa1PeTCcpWuX2DJHvupx+v7JoK5pvx0D9G8SY73PGxq/qEjRv/5yX/JNg7YeuANUbDwP3aQGAHLyDIs/+sxKYXFhQQgYCUm+cOG6paFAgMJrbOnFMf0HNl1gPDkdYI00J6AZpkkGGDfgaKiKWYtfwQRpFPiN4xLJnq3gRBy7OtbCrfpQdGltPSD3bwCa5XkFQqql6mxGq2lrgpe1edBXsSrqPtuksUc6XZ13+2izZdzlcMB84LCK0B5KciIee8hABHQE3nzpKJej7IYXiKS2Zx9EONn4xvQmnYM0kYTPVJNiCA80WI3WAHdgG5UAEuCRxyO5tsxJ/y/JBNCV5OLgdQx0stP9CPsS861JhlvW8a/lPT0Wgi1nvWIogdtMyFsWxTkhQHwcm/G1y59rcNKsk88L2XOxzWoRff0uQ0z25O7w3GfydWnbtiIXcZI/SWDEP8W7QI8DaVWaDZaTNAorz+QxscZUqKCvtHLNv3WJaJaILdCtbIwIxC2WwQY0s1DbVdYem+l/+DZ0Gs7KBYyMONyJ1JzVxP6ZgqF7HzwGRjJtRepnQinGkAXJ1wKX7VMc8nocOe1QwT238rDKw+LyUqL6YDZvtgeQpwGYQ1GreL4tqtGtv9WrmXYYQ8Az2lAupjO2xtPou2H0EsJiSi4LBlE+z0kT6ibSFY6iNnSW2ds3nBs4XMkoeKxcUhgTWMABN4XLyYKW6FU7TTV38/jaxLWnivsJBoR2nEDiD+kH2LbUDsvUV9WE12pui9IC5UlG15KxY71QNMvq7n7qM8fZYNsCa+0u8Y13KqZlPfupauiqdYAcmoc0h/9FiFu4="},{"id":"4bef343b-e06f-4b02-9a82-ced169b015ee","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据目录","description":"data-catalog","prompt":"开发数据目录功能文档,详细解释DataVines的数据目录系统。描述元数据采集、实体定义、实例管理、标签分类和变更监控等核心概念。说明数据目录的架构设计,包括CatalogEntityDefinition、CatalogEntityInstance等关键实体的关系。提供数据目录的使用场景,如数据发现、数据血缘和数据治理。详细说明如何通过API或UI创建、更新和查询目录实体。解释标签管理机制和分类体系。涵盖元数据自动采集的配置和调度机制。提供实际使用示例,包括如何为数据表添加标签、查询特定分类的数据资产等。解决常见问题,如元数据同步延迟、标签冲突等。","parent_id":"68f6e22d-b8a3-4a52-90f3-e23d8a3f0f4a","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java,datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java,datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java,datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java","gmt_create":"2025-12-25T23:41:06+08:00","gmt_modified":"2025-12-25T23:58:50+08:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"7b49efc1-5641-4ed2-84ce-ead796da0963","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"核心架构","description":"core-architecture","prompt":"创建DataVines核心架构文档,详细描述微内核架构设计。解释Server、Engine、Connector三大核心组件的职责划分和交互模式。绘制组件关系图,说明各模块的边界和接口定义。分析Spring Boot在服务治理中的应用,包括依赖注入、AOP切面和REST API暴露机制。描述系统启动流程,从DataVinesServer主类到各组件初始化的完整过程。讨论架构的可扩展性设计,如何通过模块化实现功能解耦。提供性能优化建议和常见架构问题的解决方案。","parent_id":"401be447-6b3e-436c-8d7e-a0845a921e20","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/DataVinesServer.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java,datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java","gmt_create":"2025-12-25T23:41:09+08:00","gmt_modified":"2025-12-26T00:01:21+08:00","raw_data":"WikiEncrypted:4PoKJZEjoeT4XL3d+2H6W/6FWVAUV2gnu3I7xl7Vy/iEOxLqpYxB7lCXCUAq+rosTPdhYzRKNIQy4WAdufTOJKi2qYxEJi4RQgd0QDxD33Ii/lWOFDGJVGovPk7QUFL5CExyBW/JlNem2fMAPK/+90B2FrZv+Kj/R2CvjZVEf9zbPxoTJ7ALCAkEkkn9gcr13knYXBUcbpU0gRTXFGVqjYcQIkDy7dGy/KRDfRO3PzlbWdmCM0EVFUWKc1FcGyO5rdaEXJyizzrK1qQ1HA02DhoF2W0jU3HZz83/4fbqqsQce5CQWRswY8krA6ZjXhLLWHZlrCFATJfmnOif7N3FzVKz4ql9Wx9lZqF8AZkOs6wliMUrsoV6xliiKZleN5DRegCNTDaQNnS/PUwNN2UTmVbZUx4+wugRrYGk11UJ2JQ4F0dqZMxYarlbJAvgQLOcuhuglbg2AnN9op1DyuWNxjDjUZCSvjjpOy+JqvYBgDpkjow7r9SN7TBEYljDM6WqMotmPox2G1+NyCJE9wd/5HU4zI/BE1hK9mKK5SJ47Qol/vVgj3jsq4MawBPihzr07iR5kClsTK3UR1wZdZPQWNvlN+ag/GmrBKnXrWqgIvc5ahzk7AKnrSY6Zz7MhjpieK1etglH2bItFiiefVbtqVTcT3tP6RcYwfpVK4sLSm9oUsogcu5n3pP5roDwQZ8SRnC19h43eaezVxvHBQRalsGO38CyDT7ae96FxN/1ND4lfvb0YAdqSZgGJQQw1iq3uFQFtF9jS8kC8RzW5DrsxUcEBG8Fm7a6Q+dVkjATWXlJtPuAb94dgaCAbjGUyFKfjj8b6ZFLkHoH7Dv28lyjwQJUyKizyErqTDAWNX9/t431BdEpNhJV0AYaN4lACQvVsGXgTzN2rT3mJQUB59tks3yxSnT8ayGtH8w++y8vpawxxz6b+nPfnQiLWyihR7bJVyoMqpVzwGQfSTEviMj6oVJ83L9/jMyAMEg+8ixTaY5iPi5T3nI3m9jGtxeYaggL3ArcFodNxcGMpk3aPDXFHeNeA/h9PQJSC1neA35+6PWz2PQ8xIOcJyNt5H0SoHlpbU81St+tTX1GS90BA2mTn/PA7c0OcZ8fIOtyF8ODjVRe65A/NScvMu8A4qZL7Fda2rLPRGSi1oRBpGIpL8iULcCfNcOFVdlfgxFrn9yghDwGyazQDHC8RUmhSeZPDjD7p64C3UnC08V9OF0YBIGZOHIlf0ACsTt+fEfS+qb7BlOaeEE6QyEb+pNRpd4Kd9w2Cf0ksoUz037rucHHrNtlKRXmVzA8thg75iG0S9O42mMjgu4NM3xcwVdMhnlViQlZ+i4ddlIEydwkt53dI4JQcRBFFiGtqXfmA0rITqjrVEJXrUmjBwWKvkckanYPy/+fUo5v56qHhJzDEuJ7s+k8JKBF/obAZ2XHrOseyoJJeOOl8WUu4YsT+yhKzsQS5LdKn7lcWheAfv+1KlJMvGU2xRAh3O6h4BlPUAHqGq9isw8dWefdv7NtQ9fVvj/mQr2Q","layer_level":1},{"id":"6f063aa0-15d9-4271-80a9-edc58df4f3ac","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"datavines-server模块","description":"server-module","prompt":"创建datavines-server模块的详细文档。解释该模块作为核心服务的作用,包括REST API接口、任务调度、元数据管理、用户认证和权限控制等功能。详细描述Spring Boot应用的启动流程、配置文件结构和主要控制器。分析任务创建、执行和监控的完整生命周期。提供API接口的使用示例和最佳实践。解释与数据库的交互模式和MyBatis Plus的使用方式。包含性能调优建议和常见问题解决方案。","parent_id":"c391a73d-20a9-4e3e-b13d-54fba38ef59d","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/DataVinesServer.java,datavines-server/src/main/resources/application.yaml,datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-server/src/main/java/io/datavines/server/repository/service/JobService.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/JobExecutionParameterBuilderFactory.java","gmt_create":"2025-12-25T23:41:22+08:00","gmt_modified":"2025-12-26T00:02:37+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjCSEppEpR/7M+Dq3CbVgTf1H0Fsbu2v80lMK1ckESOyKigZVIurKggYHJQ8wAqGhjCn+7wAzbOyNYPvVakiHFJmOBNet3kVn35ZLf50W5u3wbqAHQNf5cZTXt3XXvwlqJzE2RTz/ArE/wAJosis5AiN81tcBv+lWiyP72dmnmLsQROXwoCoRwoy+m2X7NJY96zjh22+NhKI7wC8KNzosBxeYdKKs70Z+qvnYC2WFrlgT1jIy4Bx1zwrNKdZvVCnCAf48AdnCBP1IEkAr782w+Kv4HM7AoFAmysHw7YrokMYJNy33tuhn/GXM+O5TQMyUNlhT0ToYRtbp0/tleE/YQlpxPZYVnLgQDH6raY08V/kwEHkPP3+/7IxOnWVLsA52NBSVmidUNPS0vJmyOCbZPP6YV9xi+nM1gmkKqVp9EC+ahF6wP1NL6prF4eVK1R7ud7MquHA3a4dtqwcYBv8EWhNqzJgtgNfszbCFUxbD5W6ig82EgjMCDkLbq0GokLQg1KmgKhOTDhhlAPEVlD98tIImYX/wz3ec9WJdk+6M8lJEaUTusTwRaTGqVFl40xXicp4GKjAFFHK+wui4W3dVQJMWrvF/ghKHOP6SHuOGgFR4d1sfr0554MhC4VQHWhwYTgzGeLfP1GFLjXsE0WmZ2TBrzr5eT8Jvo1omkRy9ldZxPMwy073y7VLGxw9UWbN+g8hYXQ5VR8WHOVZgRqJyNvMyE/8VHj4oZhnQIZkM+xxsCM7eBAfZ3+Uog3/daik2sypeEcsWt1whJZhj0UXYgLg+OzV/FRn8MEWivpIpijwr6To8zk7nyAs2mb2N2X15BHrsowM2bxuSccCWVDCC7XAKlPMiZkaudP6SdITS2jEJFRifej5qXW/gqntnwDMbtdqGZSinbAONgJctAUwHujyBYS8kznGAwhsPudPKaKOy+gxtZl9s5GXIXYvUSMNFrDGbB547PouvnYinMpxWuuUSnvYw5EAsRT6L7QPKbw+DbSqzWhdswLHq5gz3kolLsRAhpnVC01Dn9wb/bL0lcn6hqPPRmBhoCwFZHyhwkMek1HuFWtBG8zYPYZSEFXUOcY/fh71hndc0mETXxvf+Fb/0DodDaGoIQEXsLQSwsnhYdPqGSVqtxmIye9vAiD/TOf/SDgnunufrbeZg9SC50xPWrptSm91scD/gp/gXVNCqn2a1Z69eSl70P0geKWySd4s4sPuy7LcrpHQLk0fgNDUUSQJpqr4gRmMIiz+H002L3Iv1xBiynjd0kDmLoj11LQFXiemrZyrz+y4+3MuBtJGYA06HgvmFtgYVuFQf80G4MbAwYgPvjy+YUdjavGn4Zq86KBK+7Z0GvqPpOHd0NwFD3vve/DB06wg6/SpllMnefH9F3ZcDld4CNAfpQFun5WPN/9p1YtJjcG2ZZXPhFkXA+CKClgeJUInfcxaTdj9g357ipe4gbzQm5Wzulj9EtckY+J4IPNCaYJ+K5nwmWmOzEax3j/I6A0eCguFQKYPz","layer_level":1},{"id":"738d18c8-4d67-480f-b648-5c3e57f6b673","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据源插件开发","description":"data-source-plugin","prompt":"开发数据源插件开发指南,详细介绍如何为DataVines开发新的数据源插件。解释Connector、DataSourceClient和Dialect接口的作用和实现方法。提供MySQL和PostgreSQL插件的实现示例,展示如何处理连接配置、SQL方言差异和元数据获取。涵盖连接池管理、事务处理和错误恢复机制。指导开发者如何测试插件的兼容性和性能。包含插件打包和部署的详细步骤,以及如何通过SPI机制注册插件。","parent_id":"f7482163-91b0-43ed-b702-cebf50029b91","progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java,datavines-connector/datavines-connector-plugins/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java,datavines-connector/datavines-connector-plugins/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java","gmt_create":"2025-12-25T23:41:31+08:00","gmt_modified":"2025-12-26T00:05:36+08:00","raw_data":"WikiEncrypted:yP6vl3GzzNMVOI7+ToNUFYwNQlPa2hoYHyqCshVTklKP6oKvG5Dzf1sjHRXpD9MpuCt72XrznC6cBXS20ffIQnJNGPM9dV1scVK3mx4mFaXy0ZRj6EEiBHUszilzzObATtD0oP3XXnSQTdptWBVjDZJPgjF2kY+/YNVfmH9/Q8cYlPFIVSFAPuOOyJvM30J+cTo8J0o4VP/QMXa41vt8oQfVUs1JLp+Zw41IB0XS3DfUCeO+21R6RdtNRFAqqZWDa7rj47/AQw09U2beHgPKAfLsghJVstg3bKPBkcnH+/9cm22FDCQjwKPxTJ/2CwQ+pMY2yOjXHo07jsxY1Lzo8Rmuo5R7S8MMbtHmk1oWmStXNXr/Aix4kgID0/ECWZqCkXjKHdLkpyutS5EOOtJ/wCKIbnzA2kfTlC78eTXFrBmM7WrDVmeNPI3uaVyWhsXlbwaYd79jjPI+nRoL/OAbbZb2DlVqnYXfgFwe5BT0oCrCG20pk67IKQdafXnxfMp4Hgu7uG0ebK5NCj4q0PaYgGMmgWRJPtEH6dgPN2HL/qVAuHMKONg/o6KEApKssMdulF7h6N88jHua6l0mv7icerCmfS9FD/6pwDYbpCMbpK8BpZWc6PU2UDoM/5lAEnIPAuj5ICxxVRcU1s6jmr9szh9OQNGnOUhrubiyA36QipKLGRn3Sg9TJ6VJWJCfx2/CrROb/rStfT+tYks03s0e/Rp40ewHKP3TlrbNmYNlpbQFTJbZqWL196aaq1lPaelLAXbQZoOepbGUAlCgfukB59GPAVaZuzu8VPt2Pb+b/1rAzNYezxauzhJ5yseuPZOKPDYqiI63UvXuOnSL3Dt9YhtJF54Ro6iLKMERlcUTKLBRIRNDRVUx3NeT2hcDuz8oVgb3tO0HbjCyQidtOu8n/ig30dlj+/up/u4NSD+IGd/JAC08LLL+uMUh8mI7UkL5BZoqAsdwoUYYM9oQ8I4a4zzMdBEOLLiTk/vRM97Bpol7KyqIiwWxM5hxqikyA/yhBxavQopeJiHALvAPQoBLadMEW3Wcxl6Zy6l3NRVhP/omo5lLjG08joyOanaJ7zLRy19WAXhBKEOpBj7C8U7J+mDIQcoXujDyePnwuLFbXbGsqcOzryXOH/t6EQahYUsI4f3r/MLq0tLgy0r67JBzt1q9lQErVAt59xNitcRcX9LOqTJdDyB5O+3eoUZPJdlGeYqVjtQJN2tfDUDNh2ilYFK16B5hwqPmQwdmgd5GvfLmRcM0pkxvOJSmumAvHrTLxoSBGjubKy+Z82tsB2HYJvn/8Eca7pDMlBcK5qyAyLf/0ZLa4idwcTrc9YErVmue/rXq2bCxUkavyJH1Tb9WwRfvnhUP3Z1297OWlJSKf5/58x3BulAV9mrBBkHHVvWP5jbsl0RPTKLVLDrYNTFOz+yExyOLj0f89XLK7+m4ffv4s61mDK1cAypm3t4BSA5jqPLU9wd0rnELAvMgBERUR3cA0k/xYZgq+hPOnzoey1khPwdgHr3sIYbIpw6v2BFrM3XxXViZ1nReKrk8m2k0G3PBspbel3i5ZhcTgzys+SDnWgOMaxG7qIs9SWAEUQcGzrATIV009avZ8nkL/Vbg/ZhtwitCFXcWkfMa/yxFI59khndHbtjgG90cd9yTM+tH/waxwkW5nKxbkR/HGvaztGUxKB/fzmAMvyqVMviIAgFV1dh5hPN8kbUxyU/OL7zN7P1sFs2szM0RcINCt6nIUqjaohbRlHOQxAJHrIV8BHGSr820HDVtMS+yZplFMcp8","layer_level":1},{"id":"42719ba6-34e3-460c-be4d-a2d8a92e70a7","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据源API","description":"data-source-api","prompt":"创建数据源API的详细文档,涵盖所有与数据源管理相关的RESTful接口。详细描述创建、更新、删除和查询数据源的API端点,包括HTTP方法、URL路径、请求参数、请求体结构和响应格式。文档化数据源配置的JSON结构,包括各种数据库类型(MySQL、PostgreSQL、Oracle等)的连接参数。提供实际的请求示例和响应示例。解释数据源测试连接的API使用方法。包含错误处理机制和常见错误代码的解释。为开发者提供数据源管理的最佳实践和安全建议。","parent_id":"b4082be3-2f3e-42dd-89fa-9295da3c62a6","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java,datavines-server/src/main/java/io/datavines/server/api/dto/datasource/DataSourceCreate.java,datavines-server/src/main/java/io/datavines/server/api/dto/datasource/DataSourceUpdate.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/DataSourceVO.java","gmt_create":"2025-12-25T23:41:32+08:00","gmt_modified":"2026-02-05T02:06:49.3519656+08:00","raw_data":"WikiEncrypted:Zb5TNaG1u/mRrgPr+sDyCmLi8uHeMZUJIzMg7Aa8ysCN0gP/RsaD3vS/KsztRNKqe42FADyZvQLz0lzVpk9Y77Tm8jlNqFUNRypDY18xy/mNsKR5n7Lv83NhccEiyMHQIYtO4cVAFPym32k8nSE1enxcdNirtDAVx1zCJwNg2xp7c6YaeCEWCck+FxV2BRhJF8xvW6ZZ0Nfd2owi3inblEGcji8eDwYGW7TAfeFXgBpviXtK32lgBe07Gvf1DyjNcnEAlc4mA8yJuYH4MUBH0ktCUdStmFQ8j7qRKHUWf6TcePbWTciREIvxchIcmHJ5dydAZcrs7cQYEncP0B6Jdk18XZyVZWcv3a3cVdgHtsb32tCOezIhiBA3PbSLF4ITMiJGjf6PVNB8dEQpYqj54KI7xkOUJ2F8cqHN08PbJl7hJvNJB7aP4V/TKjNzkCR/lme9FPvE6/fFpvmHv3xFJm0FVdDnsZs3+44N8W6DtAh2kfMYQtK3KkLJrcEE8X6BY8o3qd0FUTDodeCWVxgdgp9i+fb7zMR6q4v6l/jBXsApcLF7OU7cem9HbaepNSB/uqltx/WghOGC+7Y5HTAXiiEo/dgeegBGXYeo90Euvyvaw2p11XpMWAZv/auE4gUcE4AN3s4ykCbXnzzUKPkbR0jRUkOEEP5FYTrfG2RzkQdY1vLY2CfyFxxD6yjzzCOpfgl/GFl4JFJCAMdmE1tVSIE1S1QgvVD0iUJkq9xKHsV4Y/w9SorRlSswZ2mMiStMXyaY7d3eQmJkAYS4unB8j8aJ8vGAJv2Ujrg+wYIxK2SEoZHJ2Pdd4X/lHRtDu6g6KRNawBtj5iHgy9nf9fju/+tg5VDLevlbc5DhJsKXC4nhmsb7PrS8n1czlULxXbYYePSnkrLcTJDE/9tYTtoAEfoCx4TZJuOLfAwAQuf9fqE/aqYQNP6Q9Nl9Pw4zL7lv69NrutsXkhYydnPHIYXQy19xan4DB6tWfb3I9oGLcn0zOh1QZbfc0UMNM40Mo5hte/cVEd8v7jWOOWstzCJJ7qtdxPbovvM2SMZI8kzaVkXet08gNRPM7P3Y6FC0caO/d44u6z/FGC+76QsLoprwUiAA7IYSWH8JGJneoC1PUSszOe937NgEYKXuBzvgjxlgwIG0SwVL2qUihjGM/pI+NKdmZ30VB1kHPrS8guwxvUl23HTTZjxpBXhI3pX8ZJsUrGPiFzF27yCkRukwhBU/Wgtoctydi45gx1UWCEl7sH/7+ywTsM6I/SeLeni5FurJ0/C4Dpt0eZFGhY4rhC3tgol0P9H+x7lTGS1e8JSRsY+mPF4HIp1Xd43dIFC2BzFB+fql8xP3KUmWIV/9o7r8tHRpwar+T2ovBmaSqZWmnvlkmmGtdxX8sdvF8Bsf0n/H2JHQRfkrIT83DhleWrKfp7DypkM8Lfu1XVss1S9Odw0PrPU6U5O4fvqbikCxDXQWbPubIx+hdfSbcy3YR44REPt6NO4y9/nyToxApM8w2PlSaQJ/CR6ts0AWTFkpVE0qewVdKjkACfvqVxNkdX4/OA==","layer_level":1},{"id":"3523e162-52d7-4f18-aa7c-94ebdec4df38","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"本地部署","description":"local-deployment","prompt":"开发本地部署指南,详细介绍DataVines在单机环境下的部署步骤。从源码编译到服务启动的完整流程,包括Maven构建、依赖安装、数据库初始化(执行datavines-mysql.sql)、配置文件(application.yaml)的修改方法。详细说明datavines-daemon.sh和datavines-submit.sh两个脚本的使用方法和参数配置。提供端口配置、JVM参数调优、日志目录设置等关键配置项的说明。包含服务启动、停止、重启的操作命令和验证方法。为开发者和测试人员提供快速搭建本地环境的指导。","parent_id":"a5e4da90-df85-444b-85e1-80088657b90e","progress_status":"completed","dependent_files":"bin/datavines-daemon.sh,bin/datavines-submit.sh,datavines-dist/src/main/assembly/datavines-bin.xml,scripts/sql/datavines-mysql.sql,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:41:37+08:00","gmt_modified":"2025-12-26T00:09:03+08:00","raw_data":"WikiEncrypted:XMvsRjFEcSrjMOAT9RAdmx9Ad2UF71tkW60J70a7giF/rZeeLJXx5CH3v8+n0MJwb8UEd3BSwvhcWiS22kJp6recMZSFAKJqgOprb6iHTBjqTUWC6oML4G6AddcJzqVlws4WxcC/NnhSKTgxmBNjXi9+Y9xYeZgSRJtoJTTrTPLSv11MH3K0fMXSdm2XvMlESh/1+NZnol7pBReV2QRQG/zUHhzkJnQVAZxKdQ8rQuDrxG/eg8evw+hcqNat83xhDqaDTQbEy8Ebc6V6y6cpULxUbe1Lz4zkbiKLyxg6keLE+GFCEI8tcmYxyi8I6ySpZaki4wHGc8mN//PYz9f3GfAO5XGrocYxcpE1JttWZ2tMnrLijzH6L5smzULFAGMMXaQ4G4AgZg5uJdGmRE36LYT1+CeC+CsgLKVN+HxS942+DZUJ6ACxzuZi67XD4D49c4wd6MJox0zGnXF0J+tmcJpNb0xHOp1xJH46lwN7hWrz6pB6deheKzUNRUm1PHlOO6Z7JuHclLOjE/0wrztFQphJTbZ2P8L1qHuzPicAouQsuY8SOaJLYKIJdpAtPefi1FtbmI45c1f+c2Tg0ttoSuCkP9lBAZ2AU7D+3zEEiurxHgaMEA+DjKdJWs8HlI2FqtwaB0JGY+KCuFwX41laNpZ64gE09+EC9lGiHXpYbaN2E/0WVG572ZO/u3I8wH3De+OlVw3Vs4W2GSxz+7nW4C0c5MgDLHrJ7Me+iozOwspXiWx5JD2VO1o/yUCN9/bx095nrD9s7NtH5Fj8iwlENbdKCzDBGbUvrx6n+0OrrOC+ZkDudgKJHLoZml3XWuV2YFRfvIepk+OzHJ5nz86nRiuLzP59ks6TopbnMeFQq6YsLjO810AcD1ANn3D3uCqLEGpKFnQEte395jNp1qJ8LTfxJ/heXNs6C0ia3MTGq/dKE2WmkdZbVggSllEA7bqg3MPZ3QG+hQixUgXBRYC4lZdGfCbkSZueprkcFhv9GiL6bU/L90/BOegnxAfsqSlvxXcKtz3bsEBRG8Qk4jeKFyIzLGpU97FYGv17bjFTTTeUg5XkEeJb6/uDaAu9nINO7N8OWVGnvuuj2RnwX3gnh4J5kuycye0u+rXKiQ/L5EjbTTfOWWAvIhgMqRq4Nev3/ZV4eCi2rNC6rD1AQoUmSv6ujMCGuuymYFXwWAIpz/NcvGaOeUHhZE/wQv92vkjLfl3wuh23NVT+qnwB0tS8t6+a8kVnb/dLCCLgISUsX4HGg+8P/YBepoqjMewKtPIiwKJHD8ssJlp/QVDHbE0meF6xdVB/uOtgoW+o5vfgir3Q2vTJv22pckXwIp59eeFsqzik94QOwyJZaPyzzxYovA==","layer_level":1},{"id":"8f3493d0-b938-4c7a-8583-86ad21b282e7","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"ER图","description":"er-diagram","prompt":"创建DataVines数据库的ER图文档。使用专业工具生成清晰的实体关系图,展示所有核心表之间的关系,包括数据源、任务、执行记录、用户、工作空间等实体。为每个实体标注主要属性和主键,为每个关系标注外键约束和基数。解释关键关系的设计决策,如一对多、多对多关系的实现方式。提供ER图的高分辨率版本和可编辑源文件。在图中突出显示核心业务流程涉及的表路径,如从数据源配置到任务执行的完整数据流。","parent_id":"1a586877-260a-4728-a2fa-ba930f91fad6","progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java,datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java,datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java","gmt_create":"2025-12-25T23:41:51+08:00","gmt_modified":"2025-12-26T00:11:59+08:00","raw_data":"WikiEncrypted:u80x2T79suuVlv00SP81PAeJFu5acOtBbwYUa+zRyf6woe/aX72bxKkQH2BV5+5PMY2nnz5iAHLisrlTD32ukCPr/3AsGal55rqC3kgorxITug5IGrvYatG3jMLrziOfqmTE6QQYw44DzCq7dFtov2lAmMEipGFL2jtsm+n7WPscvH5a8BI+8/sxlh6Xge9J1ZdwzblneYFldNfVnhXsN/63FcgmBkRvwNsiL3+D1V45Wjlh1vgaKk5x+q3bcf4NPpNbfL5rKmRIwCSXWvuIgAsQjUhmmFbYQrgtvFzJBvV8P20UpGWq9Ig3bsBBIeMXUElHgDq1mP1sIE0SBKOQNJU44p9t3TdMiIEFHnrxQwrVPDE/+IocTcmeqaw0vZX7kroEQoEz7cmHdnecqtS2el7eF9+gRwSYM50i2YrXC+BMOUCQpz3R4QwhAqJ2gQa6Y7kVGHbSaK/rEj/1w6600Gb0RkqJz7Q1W6Fo86bz+NMo51maISjRPLvRPoMNS8xFb9rrplBsAB72KIT2P0fJv6Ygps8u77aG1fQIaEp7BBNTaoHrAFVGZ3c0rJN97VyLdgulDIaCbPJWXhYkFZP2uZDgXliuueAGd9jHfHQVG3klzR0AYXZADHMzTcUhUlj/D1MWWn0YoSZkJVgf3nMkmc6DXnFwU1cs+dIUNEMBAtu9Lm4WRDOLwmU79RCmh7eLdE7ZevJlrYjZRO6CX/Fx1pl9fhxK7Amg8Jjwy/9ZL12reOHew0zmJ1x1ue6Txt6oyslODl7+HhTF1776fLC1hylAGPkQ/XbfLehSfgXb6wDXvmezOu2CrDRouNsmYeKlfdyNWHyqP9uRRzb4q2WMhHFzoTnr7UqnLJDAFweK0k+zeKjHWK19bLhUjBGrl/kzTQBomLtidyKOX2XDxnfvIiB5CvfD5fogaXUWUF2I9pXQtL31GY5v+C+uRNbc1hoEjayq4aKI16OZNw8ihxETnRkNJt673g8ZDJmY/3VNI8gezmlzZHca3L0bENaGpCnY0YmEoCnDA4Pk3CPvO/DzJuVCHdFiCwo1sZtn3Iloh+7hbr20UldzqKjNmlrDt/6mmetFKL+8KthVp5olNUWU/8f5UF0+sdnnJ43SNamGwLyYGbclQoHLedGcnMrfr3dODTFy5xV12iK27oTXTNqz5a/b/VVOccBSll/e6KNdmNCumfr17daReK3R/raFowEznYN1eqC8Gl2Q7u391tapXdjwsj6lObiJIECnZrAvJ+p+EKQW1JJb5zL7APoEbVjS1wsUiktmAi61P+Z/pFBtiusB4tNbaFbJPqGWkc2ZG736u1cgOjiKuMhxlx531wTQ7/zZeiwthK33g204Qkc3ahDumzcbrmaYH6sGeOfQPHc=","layer_level":1},{"id":"493d76ff-0c76-4864-9a2e-0a1aad23f133","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"元数据管理","description":"metadata-management","prompt":"开发元数据管理功能文档,详细解释DataVines中元数据的采集、存储和查询机制。描述CatalogEntityDefinition和CatalogEntityInstance实体的结构与关系,说明如何定义数据实体及其属性。阐述元数据采集的实现方式,包括手动录入和自动同步两种模式。详细说明元数据的生命周期管理,包括创建、更新、删除操作的API接口和使用方法。提供元数据查询的示例,展示如何通过标签、分类等条件检索数据资产。解释元数据版本控制机制和变更历史记录功能。涵盖元数据质量评估的相关配置和指标。解决常见问题,如元数据同步失败、数据不一致等。","parent_id":"4bef343b-e06f-4b02-9a82-ced169b015ee","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java,datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java,datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java","gmt_create":"2025-12-25T23:41:54+08:00","gmt_modified":"2025-12-26T00:33:49+08:00","raw_data":"WikiEncrypted:pjGuIDHO+JzqEKf2Vs2HOmHNxmuK3VN0WCFVDAMjBRB+H2H0ODZw/Z+A5A80qoLndtTf5ii0wwz14rT8ymOz2zhLNwyYSy2olxdX/teJX/z606DJKrSA9+rhFY6ysNTZjrkClXVud5VHfupw17vTssEypoRZjHHqHatn++XFHi5ws33e4pmJ3OjRWXTRfh9fBwvbggB+oWZOvLrTkmA8+N3xgFywfM50tFWkd4MgPGgl3wB3wAbuzD5lPeatE0tmfgnd1Z0r9gW157Y8A4gP/xTYHR0wFErtU9wCJUFfIhZWq0h4t9vqjZj07QDf4pn+AugPncqE0bti55zz3eTzQETnbR3ZiYl0gYt/sRqyPjjlCq5wvnvLWvfKQwtDO9UqSlmyidbDkaTWYaXxQnpiU+P7UT9TNA/0XxSSpkr/i1HaioTbaFJt3h3aYthXTwA75Alk7L7EO+JqVg5C7V9SNCl3npOeP15uBsAQcC34PdbbMy/neBxwSBMtG8LDECu683P8Hr1duwrlQ3uUf/KezfVne1UsJRAYc6KMH2PsCPSnCAnlCRrvxTnObFxZtBnoO+IyfbbYkYUtFZmpqQCElYDlW3H765lD+6jOGQEJYBnMcf1Yoza5YWexMVAnZ5ON7FVCrneQcstvwPBFFN/Ppi5NaghHB4/nUi/s47En8nZGnXw9Kmt6CW6t5ipmP4LH8KSLN6jVIiaQBxJhS5xE3bBP+kOhOUUnsx8hnTeONArQetcafxA4zSCyV3nQDrhGrfa9KgDIZGEzBJNoE8DZxmYRwnjk3cZ/lXRVnvSmmBV+icUwBL5lpW+MVrMGopUKjESZxTP7N9g37YfUr5nxnznJLFZpjsll4j1aDUEw4quVxt3oV9vI5JRKH+FBTZArctp1V1W0hYFbgP6AKqJs567ZOnT0DbKPR4HRjJlzDZzxtq8zaAOD4u7oA8fAY+fmoADI0BpNLKm0mz5D0FX7OvVnkLgwVFbZcylbn1+AI52VZwu1ENdcdCYnlxQwiMpaPMVvAsUdu/cvAOXlC9hHHcWm+3Ib83DUrk2tfNh4xD3sR2qayS8Wi6gcE+YvN8fcJHEHqbBqOiGPavKvr1819CGwCCRMulbFhsrIEdWrycr1OVOKmoJ0URHxeBUGV4Rd9T92oZTiO74wVHyJVSNDIo4nK1Pfv1yt8iIacllj854iZGZ1CC7GHV5wg5/YF9HiaoB/H8h51/yO2bfTlbt9MSb5/n0PN5mlygxlGzZ7nhJv1sFD4vCtD3AdkzvZT7nPMzIOGLVpvPccBNZMARNQpvWvYb2WPXlFlEQ0h6kDSjNF4evBTEhY5FDihB3y0Q51/jqEm4H8xtnuXI8JHKA6I8kSdW+Zq6+1EIzCFpuYfW4/KO9wWnAB5ZGx42FekyLIaK5UWvb1Nxpb5GaAT648PO6Htj3rwYZ4VQMH8aHkpIPC4qRRADuIOmfgC04gtwNI5yaNxdpjAQ67thu8KQsQBzJS4PDJWqVNg6Lh8NODDsZomStino+e09+l5fAchTyNGH00edphUMpGakzj8Sc67wlung1dd2/aPKViDgdlx/E3yehG2AX6VQIr0XQJInPT6x2nvNgf9Ou+P+lS1UJO9N3H9zb6HSLN1aC53jAHPsGv1DEeheHREQnnOgRTIcAC0Nx07UIeNQnSqfe3bmxykrlSm60ckqJPIWsTxeL5LwM4d3uu2V+Zva5lv0ekup/JygeG/6efWWrAEAqMz44wccYet/U77Kd0bSdI80kgk3afaXVSdT4F4BHrvIU/mciWygMsspaoZz0x3cjaVrCh6oTo1sgZaEdVH4Xq1lX2+0tDPyNO+JDBRLKjubBJbeDp","layer_level":2},{"id":"d6d39194-b46b-450a-9e23-15374a060630","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"服务器配置","description":"server-configuration","prompt":"创建服务器配置文档,详细说明DataVines服务器的所有配置选项。包括服务器端口、线程池配置、日志配置、安全配置(如JWT、验证码)、跨域配置等。解释application.yaml中各个配置项的作用、可选值和默认值。提供配置示例和最佳实践,特别是生产环境下的安全配置建议。说明配置的加载机制和优先级,以及如何通过环境变量覆盖配置文件中的值。","parent_id":"5d2798df-80b4-4ceb-b66b-9167054fa556","progress_status":"completed","dependent_files":"datavines-server/src/main/resources/application.yaml,datavines-server/src/main/java/io/datavines/server/config/MybatisPlusConfig.java,datavines-server/src/main/java/io/datavines/server/config/WebMvcConfig.java,datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java","gmt_create":"2025-12-25T23:42:01+08:00","gmt_modified":"2025-12-26T00:14:41+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjDVdqiAmsd9wMMZq8rmSjh8FLYWG7Zize54U3wNePVMaL31W9Jopj16LxWxpeOPxVDXwles+lkCblQqUx9LKEA8EhpdK0bU66UABRDd0YR6+fh7MR/0BuicuibiWFJORlHQfPf0LG6OOfKrtlN8c6hQTbc1eHpO8kiX2yXpgw4bQ0Y8agKx+LGsBOqY/hrPoPsdpdCjtvo/Q0SWT90djbz+uPyT0vFFz1+Z6hSYQuR3VingMOPXTiDrVsmVSn+kiF0tqSpCJ72uyu4bPUwDKILvwIr2L+aW0oAGpVvTc15hUJE6gcsIDS4z6G40bjAa9q/N3x5nOGwfKRlZqn+Ae/OaPso82x7bwrrgkvffpOHboo3tL3NMFak2ey6jop+3t7ZvREOtHZZFl4LZ2+ojMqBSGLpU+s8alV9FUHiF1gPjJCu1Elpg14c9qfO+2ThV2Yg4ZSJHjzBuTn8p2bPO02+I5/39jK4qrsoB8Y35n32goZfEPqErDQRIUClzDGuYfnt714/UqWFr+fMGsERiawhUqAEP+FymV3J96JP6E9qGHjAE0Hpe/q3irCdblUh2axwoftMUxErxEzDQVqvQeg0P72j1RVc8tJIu0l+/K2HfbUuPIweOwIiasntBpGU/owYVAOYpun7G5hHF+OrZP4pKlV1xWCPn6Jl2/hCTIJI/ErHU1d8uPfc9MsdAsql5MTb/EKUoH8ZVDTJOK1zaCKUHGRGq8qe5KNx77cS32oliEn715hu9yY5iE2qFd0cEHgiNrTeglElCmAz8Xq6n/RSQmbR5UlWBP2iRusXaCU78nK+M9xuEKjulRiMUudK8c3DBR6WgPFNsghArBLxL4rYsnwkVuhxgpdNgAJRfFEMNjiPN7sep54vq3ZNNDj2KKTA+kRw2C/SxFGgr86y5xjuhaJKV/e5ya+PWET7CXbq9W0JnNbfWLZg0xAYl44Uw6I+eNXbwh69Q4AMs26UXfQ0K5mybcdGATm8zs03654/mU6fuBcaGq2okWA/DmCsoph3sPicGHdGvb4uOSTiGfCapV2a27EmaMEQN46J+E3eo64AoTpgO1wUI9F2djzjEEmLTk68eABpVvQY43FFHlcwTBFPIT7QLLOnYGqtXTy9n5WefrSgKZFVrhnVIlwv8T01JnWfVUh80WZw0X/gEt4GMf6Qjr/YuSobmIMGTnYundoXu4kQZmzmsp7SPyqy342wBOyvpImVEvtrLQjPxMFszFLjfcmg1buLl622c23kvZW75bEZjin5E5nxwVl4YuDVj1988oLoMoDcVN05U+m8WY+AUFev5VnLw4QFJK9Ghfh8asB39gJZtSPP0DK5vOBQ==","layer_level":1},{"id":"37dbc468-ebc3-4415-b1ed-6d83eacef21b","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"特征指标","description":"data-profiling-features","prompt":"开发数据画像特征指标文档,详细解释DataVines支持的各项数据特征指标。描述行数统计、列类型识别、数据分布、空值率、唯一值率、最大值、最小值、平均值、标准差等指标的计算方法和业务意义。说明每种指标适用的数据类型和场景。提供指标计算的算法实现细节,包括在不同执行引擎(Spark、Flink、Local)中的实现差异。解释指标之间的关联关系和组合使用方式。提供实际案例展示如何利用这些指标进行数据质量分析和异常检测。解决指标计算过程中的性能优化问题,如大数据量下的采样策略。","parent_id":"43eef860-d2bc-4625-a145-101fca77c030","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityProfile.java,datavines-engine/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalDataProfileMetricBuilder.java,datavines-engine/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/SparkDataProfileMetricBuilder.java,datavines-engine/datavines-engine-flink-config/src/main/java/io/datavines/engine/flink/config/FlinkDataProfileMetricBuilder.java","gmt_create":"2025-12-25T23:42:15+08:00","gmt_modified":"2025-12-26T00:34:35+08:00","raw_data":"WikiEncrypted:YZI97ep9QXDPfRNDXs4+JNeOXqHI+qEl6wgA/dLnhCsC+JsjxBZWhXi3tS7QbkXeihs7Ggjge4Wyhrsvty5DI4p5JsfUvHNfgzGwimYG8kQ+fHo7kpEPew9xBSVwfuMom06/ISPaOlCmYp7/I1+AuRKvT4kXnMd47a4UilGBrjyWwXA9UDbwzPh10v8OxJu4hfZaU8CvoEU2a0FDduGUwtFwi5g3XKVAwPBf2xPm4NPzmujqXKgXZXgv+Xo0JCewdRvlxAykJMr82H3BnyHLo9XKU5b4NRPM8wwMS8w6bylJUA1Ix2HYf+O/DUWRlm6zL5uyhiBdu02jmzggKFemqwiuaMmgE5Yzi9KRENWWxqGk7225QD+r6l1lwmkH1XC2oKYNjGDW/4+GjMVzt4Kki3xTD6k5InyTmN2+64CiO6hbj3J3rj3YyJwxSZojZ5H4+QaEh0STeSfNGS0g20neKJYXYQUd7Ou0ocQ+rq3lT/mRwOGLmS4ZiCD+6o+3vjmep6zgkZDUCN++kf2klEGoj2q9WZwCI7AQeh6cKAscwqSW7MI+ZAUWsdJJexPvSh+Po1+mLWETMGHU2kn+imWslSvbCgeNMrA6Ios0TCa1dU+v0sujW6PK5F3lk/h/juDEIIyy08SgWMuuvrxQPMBiw00tfSzJn4yXFSSlWGox/5YaDGjhemEP7GH9ehE0O6ZD4GZB3zPU8+bZDMVoe3gMyqkov5u+x1mNHhjdjesx9XM8QKAiXsyA9u4ihOBZUkFm39IR4wiSQPo+KcZsvrsGv14qGS1lEInk1wd8T95+jdoYrMbCxXH5oDfBlz5uKLhW1qXr9/k6NAMDVRc+s+wXs/UD4Xitg4oKkgjWyF4v3aTSgP7jUBS7Y8tN8xgiKa2ybAOllNZx5U7HPjSWE2cE1GaON2V1PJ2yJ8XfRrUsQ34ec6JEh439t1vpRSrwq1+SMGAPFh2mQ7Q0Ka8KHMoWjsp/HCMq+xa0LOBq723DR6wbGTTI3VHpjYwa6Mk71lVwHg6PTmSrOc9qXECSMmCPowyysEa5TRU/ssjbsJYjnGuAjvpZUWxhio3941SvDZuMiUaPsA8n8EJva6d+YwzbUqrKBrM+qJ627h8EBmWUgQ3Etd/hWA70lBaCoKSO1sbP9I4EfcKNPzYlLrNBslWxGvKu1AEvpbMJMUAncqRJL03zSi+AJrzWxg4uOnmi08e4FVXSlZ8HMVRnrUDqU/GLePiyjy18kKV9on8CUWldF0nGCFsVhr/NPcTM2ryVRrk9twvsWbz650+vH4/5kXcdLSUtgN2nwzYVJ3Y3TFcBPk9xTDCTm7gkJj2r+sDHcpa/os2wkvvJEAj+xBZWaBr6hmfBzPEQe4DRmROZCWBSuzoll/W/vCvkXMzKFOaYGVlAXJcsxAfwp5LcdcVkMWVfe/9TFK0jTiNOvdc1NeK+IGAh9q9BX8NPAFlCiswX0/lcJf6VEcIPmBUQV+dHG2lzhEeXjSIzf2sFqqluYy4JpO0mgup4BBrHRa2lwNMBdWs600yp8ATYmuyIm+g1uQN48SV/SsG9/ib5oAB/b+hq3eE45JwwvHAW1sa3ZHaqhcH6yVDWRQOe/LJm3JBHRwk4daj2CwX/ILAwxfgOz9dQv3BlO9G2BgaRBh0jNw2rdhQYq6WXaSr3sgd391iuV7ArbPOuJrg03gyuHW7j6SMUtmekx308DHK1T43G6TwvyNb9SjizrlRUHkZwUNzi9bdtVpstm0eps90hP2DHqU1XN/P4dbgx1b3b0Vfh55jERd7MoP2dUjRtlp/bTziEY0OB9M00BPxgl6hZCjkM73/pmpfacZmVUG0RoDb2Wm/r0/psr8Ql8xhPUE/2jyDrGXzaqA==","layer_level":2},{"id":"5a95842d-bb17-4f7e-b3f1-fa2cbb84163e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"组件职责划分","description":"component-responsibilities","prompt":"详细阐述DataVines三大核心组件的职责划分。Server组件负责API网关、任务调度和状态管理,需分析其基于Spring Boot的MVC架构和Quartz调度器集成;Engine组件负责执行引擎抽象和任务执行,需说明其对Spark、Flink等计算引擎的适配机制;Connector组件负责数据源连接和SQL执行,需解释其支持MySQL、PostgreSQL等20+数据源的插件化设计。通过时序图展示组件间调用关系,结合代码示例说明各组件的关键接口和实现类。讨论这种分层架构如何实现关注点分离和可维护性提升。","parent_id":"7b49efc1-5641-4ed2-84ce-ead796da0963","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/DataVinesServer.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java,datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java","gmt_create":"2025-12-25T23:42:16+08:00","gmt_modified":"2025-12-26T00:35:20+08:00","raw_data":"WikiEncrypted:4Zqjl5aZEo1Vv5NKBpebTkTkJnqMY6vRji3zUx2KWI5YHz8pPkMMxzSM3Rs9aiUqH6QohJnaQQldn4IQtoy9tIkLygi2XSn0hzlKBoIn/S4RCwwX+t3n5fZYJCKR02eYrFBruyrXzgn6bbFpPHMVaJsVQio+FZjA/VKwGFgAgho7PMbfEIeoOjK2Oi3Si4E2zhUFjk2RRJxp677curhIVhRJFw/scfbKa8JoyrPy7jJiBUZh/4Zdlebruu4QzzNR19vKlgIrS6MI0xxOxjN5RhvHYfrYeIkZq/7n809mJUmexUFBw4iCW+uw0DoZ0u2ygaOIEQ/d+OXBVCvin9YDwlLducyfjW5C76c1xCTiHhKefFBTnVopl3bccFQEdgPd6CsjVlddBopX3A1JC7+ksGn41MQlhbRCVOSVkc/iadho9qy3xHK0Eu9Zcog4xIMOwWPKrMkbAPWDAZWPHKm8W9bmDPYRm2YVh/upy0imB646LDUcJTSh/wxktje4Xs6DIbCCOvfxUxaUwMqGwnmLxXgnAFDwaCja9rnM7bBF2p7By5PXUMGASkhfTabFFmKW21mrhijD7hVXAZ+Tfnoh3guoALHKdu+aq/bYykV7uHETaEPHoqBKntvtWLBtuW5Tp+MhMR8nV7VHC+sbUf6TYrH85wnnDknrnbtav4o8hHlfHFotca46mKEz7LMFNYDWTX3+Ankv3beLQRe0KGr5DM4qR7SUNcK9o5Ui5Nyj+zviywNF0b1OgtXvUBjgXGcs2TMp01VQK5LjL2cGxUO3vJc+vkMoBBE4nh0gteFhUDOP/jUsd5mgFnVu1xxMyHBHk5RKwF+gHDNsHqfyxDMnfnLAv5E3GlNtFeRhtfPzt6rLT+yN9P+QkiaXQZPWw6twOIwVu31EDeBfuYZxh4RVAF4w59YmDNle6iVvScuM4IJg9yZPto2cuydALsDvq+pde5L4DF0uUtjY3qnyEj0VKPlxuOwOYQzfTxiyP6/P83MC9Hzqi91qHKV+hB8zxlgO/Nn2jm/dMlm7hK/jpdy3eJSpzSenye8PaQewUYWRT7TgoCh1AkQThlN/R8dwK+cltecyWMI7KG8nVNyZWoWotkWlNfsKHq9qDC84hF8owUdel95bu+nPbPNr3bTh9+6S2LZp9D5Eqiol6TTsrOA5CDmGeQP8tVXbzIYRFL6HYA5426vK00BDpnTv+x7v4XQtOc6xxsrufTq2wbnSf1RKOBmHtDxfgk+44pjiHRLwnd1XwiBhMbXFLuCE/WXpF0RwpXFXrbG/DL0X3gvQmsM5RmF+XCu+dsGZHSNUHf8kIZ245OrY9uBVMTkSGeNxt8q7i8rVPwI7QJa/O8ZIhY261wYDtYfww+r9GCCwOPdlhn+RVfxidoZnZ5WjVyW4H4ptdL86pRNA081F+M59ElTlYS1XHNTpMdiV4OCdBOvMKcnQGuwEX/4LOsZUaStMZhujVYPa0svddtmc+QFgyx3Q5PfGwu0y0jqPURdBzNKSez3p71ZV425395vO8jNZCoZoSGQsx42L+Zsi8hPXuxtURPILMqCkeJpSe34xpEhfM2GfwwYEAXTQoulc89u5yv7svk+evPOhvqDGOqPtrdK3aM0viU9fQ+R+sKfwFbtoRP0=","layer_level":2},{"id":"9b5eff2c-3130-4124-8dac-52560ca652a4","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"检查规则","description":"data-quality-rules","prompt":"开发数据质量检查规则文档,详细描述DataVines支持的27种内置检查规则。将规则分为单表列检查、自定义SQL检查和跨表检查三大类。对于单表列检查,详细说明非空检查、唯一性检查、值范围检查、正则匹配检查、枚举值检查、数据类型检查等规则的实现原理和使用场景。对于自定义SQL检查,解释如何通过自定义聚合SQL实现复杂业务规则验证。对于跨表检查,详细说明跨表准确性检查和两表值比较检查的实现机制。为每种规则提供具体的配置示例和实际应用场景,包括参数设置、阈值配置和预期结果定义。解释规则之间的组合使用方式和优先级处理机制。提供性能优化建议,如如何避免全表扫描、如何优化复杂规则执行效率等。","parent_id":"a19e7b20-774f-4c69-a930-24d3fbcd2f0a","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnDuplicate.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnInEnums.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnMatchRegex.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableValueComparison.java","gmt_create":"2025-12-25T23:42:18+08:00","gmt_modified":"2025-12-26T00:35:05+08:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"26db8717-63bd-4666-ad5e-8d31dfd21688","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"SPI原理","description":"spi-principle","prompt":"深入解析DataVines的SPI(Service Provider Interface)机制实现原理。详细说明@SPI注解的设计目的和使用方式,解释如何通过该注解标识可扩展的接口。分析服务发现机制的工作流程,包括如何扫描META-INF/plugins目录下的服务配置文件。阐述接口与实现类的映射关系管理,以及默认实现的选择策略。讨论SPI机制如何支持运行时动态扩展,实现核心功能与插件模块的解耦。提供SPI机制与其他类似框架(如Java原生SPI、Dubbo SPI)的对比分析,突出DataVines设计的优势和特点。","parent_id":"a8f7f5d5-bf23-426d-9273-02f47623381e","progress_status":"completed","dependent_files":"datavines-spi/src/main/java/io/datavines/spi/SPI.java,datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java","gmt_create":"2025-12-25T23:42:29+08:00","gmt_modified":"2025-12-26T00:36:19+08:00","raw_data":"WikiEncrypted:g+ChWFecf3LFlKeT6ZiZbM5WoDP5yOmCKq3gr0SNFgiaERPt8CWxbtMldoH3KnRCPkJXUD855NSHK4Qyblw8kOteUkTs4iNPsL7FjtC+fErf4gpyfqix84FKaajfHLzvOrr9vl/LELXvc9ZwxpnbzSOMH/yuZsjupQD30h0wyJNRCT+N4+cDSTTymc1nMzp9HptEkXfsE72j9EV9vTg6b16xItbEIw7615MAjyTHcPKlOHwftwy80lTiarx7X4+nKnFksvuLsp+yJxK6mocqJ6OeqTL0XZUVIIO6VcB/OMJzuUeEe1X4hNGpHq6+7DTdufbyE81NWnyyD81l1EQLAuTgXeeSM4mgWlEcgHCk9f/JkTJlzNhwwRq2PJuirFD2eW9D9IFPwJdAnyOvZr5do4AwtDYnL/KaRllY6DnVnDXT31ALvzz8cQ1KTsJITajqECX4ReuJTqniBUHori7U0AiPHKAPlpDzvirpsiHgmeI/6ZnMPH9OApNzDyEnGedFsiMTOx15Cng66F7IZfa5UPJiebDPXScikt9xRuQ1ScDInf1YH3IzSPqFIjI4s4bbcg4xo5OK1PGBtj17aBDUO5lERdSO+DQ/cjGbQ9ge8/D6aSMQK7/3ynPsT5DThDnSqTQBDyUvM3eD9FE4yKvzaZ5u61/S7Riy1ZFokvEYwO+lv+1+RT9vPfmyNQyRq3SAlwC9EVZzwqi5fuZG/iXeVPDsoe+Rd3hDyvSKULA6ARmOfpBtjvW4CuO5jN0EVsdXbG8gZMkT0lFb8pa6N+INTTkb7X+zcK+lU8sGnmgGaXfCr0FUMxZ47G5hEktZ08vgx4nvGoy3lX1zQ8XSiAn7L+PPt/UPe2N8iC1PgQWr/kNDBSSE+0eqsI/emn/8rrkpaUx3/BjQ761KcdUdIyMbcotLanfvNqf597jZ+oUZgTwlf2Nnd9/xiXs3/OSKSUV4v4FNAl2C4zlMiG+sJX7R1vRPHmgc0ear2KBeHetIUY4PXoGihpfZw5j3QiXkzeV5jtSDp3742Y8yI2RaKVYu917c7GyPWrZnUrPlwMfps0aMnLRPyKfg32GLo3Z8TU4qmR44EAeQOdRwPu00PWDg4OyV+qLbBP7n5ILkivUG48YF1eDN5cMh2PvjAs6jDd2N7AjHcorpQzMXxAbkFwtQBm2pFVWdy+wLAjz0vtLF+OU=","layer_level":2},{"id":"869ec0d2-5e86-4aa7-b6e1-d914bbf8ae25","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"请求处理","description":"request-processing","prompt":"开发DataVines请求处理文档,详细描述用户请求从API接口到任务参数构建的全过程。解释JobController如何接收和验证请求参数,分析SubmitJob实体类的结构和字段含义。说明JobExecutionParameterBuilderFactory如何根据不同的任务类型选择合适的参数构建器。描述请求参数的校验流程和异常处理机制。提供请求处理的时序图和关键代码片段。讨论安全性考虑,如参数过滤和权限验证。","parent_id":"4e0ed203-0047-4f0e-b2d9-d7fa1cf34621","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java,datavines-common/src/main/java/io/datavines/common/entity/SubmitJob.java","gmt_create":"2025-12-25T23:42:30+08:00","gmt_modified":"2025-12-26T00:36:29+08:00","raw_data":"WikiEncrypted:ZGBkpWf02wc2udcy/W652kANB78aZ2SGCix66ME4yKs1m9QxyIgH51+q+WjE95uf1TJfPVtsV//lOheUNTYOwCpsLMqTeIW/clsicvnhPJ8btgTH9Je2SivT8+0X3l3bpS/Vcvo/kwYudh294oWZ79zXVujPWWGhzgKWq2FvhAMQHcWPfyvVOMRG32K0gushahWhbUpP6DJcqSUbr+n/3vOD92o//IGdOJOz6XAnSZPz1o0Gk+w4/sQLd0JSCxmoBlIAwDgaTBHkpAZ9op43ZhGW+DLj9ijfSIUe6PRzETGPxbejI+ZqLFL/0cWgvaenqiONb+IPAD6k3b1qFtXt1itxN4/SsqPLwq+Z+DQiYPIJD52+shYwdu029JtkptfS/y4woeKaZIYx5bpA6SPf8vJKy6+vdCLwkmvQ4/YbdSkgy+l4OZDLjiLdUN72g85o4q/IEnW6xjVNqYJ9eH2GsASZSV6N+FbvkLPr47X9B5J6tc4vvHan2l2/1OXt8aTR+3YzEDosrtJGzdKYJp6epH9u7BAn427n6okmuzVDE6XGypsWiSMoVkd+TsVuVHQh/B+h/tbHrv0d+mwKZz8OBOPvOfmPiUpfEugAs4fX/2r5ahEj+2viPGQTi/1hmQIe/vQdZggidKI9m+eiKo6V/a2cLbbYxA3RlUAgH8VRZsqWEHXHmr4nZ/WlR9HQt/zJ3O3KgZYhDOk/FfK+KtPMzmrjaOQ6kL5N5eXD0dSIHFMb2il3WlODOkoSmszdWFw5UoeyHJeKllDpjHvbu17qEHO7yygWbGdcysyW/zxHl9R1J7sjTC4NgAlj37ijGAjUxPkrXJXZQc8ao1X0y6kUzOnJIWg9QBog/u02+m22b6YFE6rUY/jmWuFMFG7esIIzP1k+TK1o8qNiRW82WALOZQmC1oGKE7+Vky/ILuwr8fgqQ1Qu31ZdbE92K8whCk0DTOALKMDa0uf5jSXY2RRfHdzFeRMnzDurXCihE7p1fTRsbLtRcZcdDokfbIUze7sADN/1GjZs6iGs7GjLlu8aJqp7hhMyuYJ+BK3WkKLtaPVA07DbjDDAEObMq0yu4EBQt6vkixhjGnX7GTrT5PYaace2aXP+z3Hdes5XgOxMNa+bW7Thl/FxAbnbcidlGVteuAdMDK6ld+gp2D9pbRa7LbTQF+OtVdnL3052Ad2ViqkoYv6bGX+JbJjsH2MNnaUxHI7U3VPZm/LcfLq8Qtfdd1nR63gCoeOpDLhVD1OefvpU7Lz0wJ6viGD4CHRxCUMw4PIYhpxW8orFxY4jG1TXljHcxEcIptx3/277tnFUD5k=","layer_level":2},{"id":"22137116-d139-4038-b838-9639aee8155a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Quartz调度器","description":"quartz-scheduler","prompt":"开发Quartz调度器文档,详细描述QuartzExecutors类如何管理调度器实例。解释addJob方法如何创建和注册定时任务,包括JobDetail和CronTrigger的构建过程。说明deleteJob和deleteAllJobs方法的任务删除机制。分析buildJobName和buildJobGroupName如何生成唯一标识符。阐述时区转换逻辑在buildDate方法中的实现。提供Quartz配置最佳实践和性能调优建议。","parent_id":"5856ff4f-874a-4522-87cb-4ec444ac1aaa","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java","gmt_create":"2025-12-25T23:42:43+08:00","gmt_modified":"2025-12-26T00:37:27+08:00","raw_data":"WikiEncrypted:Pkfwn5XOIad2zhpXX0eFFJRs1yLYQSJBTJK6A8C9hyQelPZoYlKcrfRcHuOms98wp7cBEZ2/yqHDI9TSBWCnUmE1d5mRCln8clGHxzi2JSD5Wt729EU7Pf83P9Ps8Eg4KAbs8r8VfH+Eqh1tutOZ6rRH2PwZ1NKwUGnqIWB3trLsu1XSE6CyiWTii53e89MbNc9vhvquxzNwxm1iWYdB80A5WE9ZWM6X9/6xQxSyqTbJ3OeknpHOcY0K7nZjDyRzx+NDYAOQqq+rR7syCXYp6ENnf1fs2dRFqAeIiuEvC3OOn8PcC+XhDhd/GPrY5GBt9OVZcubxMgZ1L9zynJscEt7dQMtYt5C4hp/KPQlf7T4IG6d4bDCjtWcfBEPEtT0za7Yk1Zl0ppALrEtMnva79cwMYhmm/UaCFI2zz1UbHzRUwL07sbuhSgRz7ptuBlRfk6ZZLSR5T0CANqqz/fdlzxYIeamWdwFQJ7V7F8ReOzg+lmtcgvYyEK+amiDksQ+Q9EMt2BALZSECiAllx7XxMllYO9YABVvvpG9SLz/KdSep/y+j3/Fiz5uZ+aOR+qnUfRQ6sA1n02ToFHjkzjCQOh0zA7YVm7lcsVemv3fPK4lt2k6pPzg8YvTFquj+DrPCWPrHQGe0M+FK3SZzgbCIuiyb93yisbbSn4aiNssaTKDx3Qk1jb7bJAw9vBDymywMqgYGmvoP0L0ogVssstwnoRVzHykXUEagQ1y+tjW5G1jn6J+a37B3ZbJ8q9FLQBceC+3N7nLWdgtZclnGIJaTMHd+DL6JjRstYi1WOZUzKGziq4YoBOp5MIhNggcts4Y4g0cD8qqVVWWwx9VUidp7276m+URg1CfjNdwLHdoYl7xB4o72EHTaZCA9hDBcYSctW4TXUzzfbXpdIOrH0hIBMOmj9u14nXNl3+0pM112RNs=","layer_level":2},{"id":"ef047570-8c35-43f0-8ea7-de306e129b99","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"注册中心接口设计","description":"registry-interface","prompt":"创建DataVines注册中心接口设计文档,详细解析Registry接口的契约定义和核心方法。解释服务注册、注销、订阅、监听等核心功能的设计原理。分析ConnectionListener和SubscribeListener回调接口的使用场景。说明服务实例ServerInfo的数据结构设计。描述接口如何支持多种注册中心实现。提供接口使用示例和最佳实践。","parent_id":"da4c595f-1508-456b-b54f-fd0b5324fa43","progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java,datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java,datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java","gmt_create":"2025-12-25T23:42:58+08:00","gmt_modified":"2025-12-26T00:37:32+08:00","raw_data":"WikiEncrypted:hvwFz+sIainc/WWi9rXmKRgDo/GQVuyK5uig1evGQP4NCgUy3FuDPGdgsPZcYMIfbwuWTtLBeIQAf1NqScwYjtdB1dEi7Nj7lOKh21SNzw6V+btAp6WUZoCvFsN0AR6jqkfgpsCBx+b3A+cfDRW5QE9jCR9B+vGwn9ALdiRO9PtD47uQRiHoR5l5i+muxTSox+bG7qkTiZ+C6/AlIZQy0V8PcHVhXRN19WeW+vvzXeAb9lW94b3NRqHsK7fNfjDKCODj0pB8hoaLIJ0aLajsQTIDzGNzDNexjtGXzB8MD8CJlw5QtWP2zbF0KBeGcC0JhAYC4NB0llYCCkoK55vHqBgYLk6xGTZDreTi0/tv8XZtfykrpLpo0ZCi3kS9nwzi8VX1oGmRAI3kbLwIwafm2HzHbolXKdMMTubjZA3mNarA4/1nwcB46n/wUP+TmD5pGhagZRw4lyTi1gYzveuWNcVRfcSr93+UlQh3oJP0nolyJHI2RSv8MoMP4KgnlF/K19wqfIZHjJ+l+2mwAnovljTvhIvdeoTptpL6UoFUmZS/ZKFGFQmsG5+1Tbo47Nkj7rk2xZRpfpU8Y86F/mu3PEU46C3/qOutY8XY2w0pXo/1SOzlWNU1ItUIrW6l3bwoLM7gl618+9W0eEgB4cfXgNo2pLuMKJTlOji+ZwSuNv5NE+sqUELfGbMEdIi/GwHn7AlTyXANnso/P8EisuwLKopZQihDXbzZlMD6FxMjFL60abAqaPW2wqQ2qoUDVwDt8k3bCW3Ys6ddnDFJtARAzJtsMTHQA37+QcQOttm4l3TKZdVa5/iW9V89WsUuFOB97Aajdh7ovxiA3zTi8dG8n1Fj0CwJX/+wVBcfI9kUY4x3MpvJ7xQveLG5yY5UlNSP1/avpvRbK2jQZQyiNGl7JC7NjdPehP6jdESRRbeXprOMWa4QQxtITFNF5n1kmI5mUc78GQt/7k5Ayk+oUr4ukyjgnMf3EEstYasZMxpYfxWT+3SknLbCtFxZKFJ/x1B9LgQjlSa8MqxOKgnPOyx1sJd0MzGqoGzue3fv2mr22x6kII1L0gMv7yna45HXNsplbgjyfWXw3IrounKUT3aOePE+qkBw2iY1O0LdoeIRdQEa0gb5sQdpYGzg1kzEdVJ6/mSVUUaTEucw37bwUARTTBbpgCYQZIyl/mqnKtEvRKpczzOjqAhHH14iOb+gK+44IUXOLfyZqnfuJErnHE4Av6fpS+i2vR9VORx/aVN9SJA=","layer_level":2},{"id":"a6d66cbc-1305-4155-8e13-7c3c40ae68ba","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"架构设计","description":"server-architecture","prompt":"创建datavines-server模块的架构设计文档。详细描述基于Spring Boot的微服务架构,包括应用启动流程、组件扫描、配置加载机制。解释核心配置文件application.yaml的结构和关键配置项。说明Jackson序列化配置、Swagger API文档集成、MyBatis Plus配置和Web MVC配置。阐述服务的整体技术栈、分层架构(Controller-Service-Mapper)和各层职责。提供系统上下文图和组件交互图,说明与外部系统(数据库、执行引擎、注册中心)的集成方式。包含性能调优建议和常见配置问题解决方案。","parent_id":"6f063aa0-15d9-4271-80a9-edc58df4f3ac","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/DataVinesServer.java,datavines-server/src/main/resources/application.yaml,datavines-server/src/main/java/io/datavines/server/config/JacksonConfig.java,datavines-server/src/main/java/io/datavines/server/api/config/DataVinesSwaggerConfig.java","gmt_create":"2025-12-25T23:43:03+08:00","gmt_modified":"2025-12-26T00:38:27+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjKHMQu0vbqOQrMoDLwN7tzzwfD5gRm4yNIwO/VEz7D5KZ44MSuuoKtnALL4lpn7nYz1LO81UXcbhvSmrIf1Wl//MeQYlNjidJiro/Q5Eqe9BZ/2v+thUjZZmBVz9zSLmqTY8/h+ilPyllxCXMYoikSWzerrjellQ7rYWsfjTuWe6TIy9Do7/rXBhmrKO7Rv0o8bRtkBf+nHDg+9CquRLh5xtrgmVpO/JfWmplVLreI2PMYq1593Kc86cjwDPrhGG9stesyzRLwAdOUrnINRhDlMC2R6ctQg9l/BcL9bZKKw4UoUvLkpn1xxYe0s9KLbSOmqbJWtmGqvE3wDLDuRqh5Jos2nFmwbaRYosqpbB/Bx8MGftkgMNaz11Rj5U6Pv357aVlxJe87gFXTH6cLzwWT4yl3gTzFgLPZC5d9RB21FEPn68+wuhgSdtAot4eJ+gkbISjvE26xb4/Cx9BGDGTWixExWfMmARIamee4FyvwpermgkZke9XkjwN9ncXoDSfEShFr+Z0/GZpU/wjgN/NoILyKSPvLYzL4FnbTrY/KPhsAvpLWTh95yQz0s27YQF5n2cYg04ta10T859eIarvdIT+POBMjsxCgMq1CnIWFqPiTMhwoj07moc2I8LduLSerYnM++A6Qg2swPZRo+Mt4RiXuoq7Z/F6suCgolsgXmLLriyNsKjN89N1N9ACQoD6NV72j5fCUwGkoaFVxSmCmCVUjooMpWKkF19nJFXYS8NbgP6idnPW+AEx8a8hmjKKUe2ECytn/brQdlrpoh0ItVDVLBcBivb/pJ4LAhpPPYUuYMMxAg47AH5bavX1bIvpTPF5ltK7sTPaGUlAeeWbyRMXioH3N7JjoeSFk/FQGTjiNySyy3YTsERyB3J4TzLOOEvooNBlh2od9jSbUAVRG1TWLvLMjoETqg4iA3k8W35sDbw/H6+WTt3VHDOWiN81TjYmcdQt+u8OMXc7eeAIkS4cY/Nbc4rM0GdHgaRfqVO6L9vWza2c/0g1L8uteuBlaKTyCjdMv3AJfR1G6vOtXwd5PQlvIxV9EDuWoMGX4D/M80YgCLiCUHVQJiPyBfUfEMbrg8DPVQqPGcEpMoabosuo9wohssx53E8e4MxvGt7oIkF11rrN34VHhgrNdR9vOgVRqUG74AJ29WLT4YsJblXY9KiUPcH0zojYvUj5DGZzapm1i8lQqrFrsKSKrUQLZMyVrJLB+uu4RHbw09pwGyoeN46GzPz6zFegT/6JtmAR8Hg2l8pXqb0Tnx69O/wp9Q7NEDCBvFL0SrpPOiTax/3ftIz8t61NOPQUYnKGEEVrBydqQeYcm+XhlviK9aJy0k8TpnNS7NUZODvJqMCxh4xCshK60ciIDlnv40P4h4K4MCmuSd4CSMm4xV6BIyeQ/CE7SYOH2+5Jw1gpvYPqpJ/kojiIC2wytDb/WjZjK8fYdi/pncXY0o+6HbdSzc3rw==","layer_level":2},{"id":"a9d483a9-5eee-4f59-a1f3-8126ea2604a8","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"核心引擎","description":"engine-core","prompt":"创建datavines-engine核心引擎的详细文档。阐述BaseDataVinesBootstrap作为所有执行引擎的基类,其初始化流程、配置加载和生命周期管理机制。详细解释ConfigParser如何解析作业配置并转换为执行参数。描述ParserUtils和QuoteIdentifier在SQL语义解析和标识符处理中的作用。提供引擎启动和关闭的完整流程图,包括异常处理和资源清理机制。包含配置文件格式说明和最佳实践。","parent_id":"bdbc7ff1-6561-4953-bfe0-96e43c8b3e3b","progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java,datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/config/ConfigParser.java,datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/ParserUtils.java,datavines-engine/datavines-engine-common/src/main/java/io/datavines/engine/common/utils/QuoteIdentifier.java","gmt_create":"2025-12-25T23:43:15+08:00","gmt_modified":"2025-12-26T00:39:10+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJ1KknUwxEcU6WrG3nWTSBTTY1osoS60Db0IAlCNMIqZ2DOcmQGv8T5N8RBFqJq5CJn8/tc9RUsBVajEtqqVqQ8BK8kgucrmtuULjkQs3sXmf8u5PO/wLRwFrgviDbOalUZvzE5PE7xgjQWBnz6s9WV+RiiWoAYlk828yFPVS7pZ5wcPTwSg5aHkdj40QE0dh1wy2XoNZEms7uFWgcO9QuUbfIad/nBb4tOG2YPhPf8WHLLTifUf6sjVg5rJ0RvJJTxAfMGF3wZaMuYmD4P7vJ/RG8Sd2wIuDzwGP63womJJoAX7Db3cljDcNgN0db5TGImRslQ/7dmJj1Bc9FNBPbRpTdvZRaz4UCsP7fl4NfhNAPw4VWhf3VtEG+X4ZtwUmfw4ZIWiw2PcCSal7MZuEn6oTyrLaP18p7UsEtsifoeExIaHSMOLg+4kM5Dc8KhcEnzJ9w9EaNozMEzsWBkzIw22CKj9xIdR58uFgJHgTnuoOfH2SdTpARzWBPgO9n2vnLoA7M01lUFi9797rTh5LVmEHPGjFOkts97AAa62tI4fneMTdk8TCtq+f6/0KBsqkHli4jl4sFgstnz2obJinOcx5ynM/G4HrEl/6eFPDf35jRqPRvEXC3+Vw1Bus/K6Z3IudwoJPecOsC5gIjx0dQ7AR4mJwMbyVE+rN1l1/wzQGmIO+yh10fipuk6/S7K+DLJYChHyEl+Xu3cZgN5VAJP165Pc89Gt9V/V3qj2tWeEwr0tbo67HMFp99DeCjgyzX4hHEWwaFSTswuKMmkq8davXUJiFXkWZKqHrBDzzGKMZRwgmQUF4tClOPxzxWdekJ0TjKnhvB4uJuBSMYPmfSxgdxjx4tAHNBCcjNzJy9MbWm0GQj5w5De3jY6yBpY+QOHTZ6tikMHFTfGfd1sXWSEMhVKsL/rG1qAJ/HNXuZg2Qt41yiK+RMDUZNwm8WxP4XLUnkhS6I2mESPYYHJbo2jGlpgXM3uhjtBZMGDlcfuCtXEgLdyQW2tGtm7LDihbBEsh6hVN+SxSu37vT0YYj/yEtKmlnl6knbH6uk6311wqRZESmFdy8+ryGJ+8/hQTXm9YwgIBZwZi5mhwXGcehB3v2/kZ75+ve9lQW++fLxhKFWhLyd7VuoFC5XgKy/2aJugh0v03y8XZJoAjrdLdEEJNBQO0+H8Vqhx41N7jRHUXjN0Fb91ytC14y4u8eSDjoZegL0Yk/s51ErUSSvmkDcPfITaPdkrqYcafE4YYKwBSsfUG1kHYHYE0gv4AdXpy3DHIvGwkb36Dnf2E5LSeUgzkZHnSuaZ2ffFFc9rcZZRH0JguO5cTheFvWKJNJK3H1ZsQ3Nmlm9Q3fiKyq1ZffX1bMalnQiYCSNZC+I7lmLSKGeO9xfb7g6NJ0eQ6YR2VIbS8CfwochLEzF+99ddq1yNCD0nXG7x5v0QKbVn+2cAioXRyEdZAe8+Yv4z7g8SqiSQ==","layer_level":2},{"id":"b75cdb0c-88b8-4bf6-977f-5fb7d26b1ea1","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"连接器API核心","description":"connector-api","prompt":"创建datavines-connector-api模块的详细文档。深入解释Connector、DataSourceClient、Dialect和Executor等核心接口的设计与实现。详细描述SPI插件机制如何实现连接器的可扩展性。分析连接参数构建、SQL执行、元数据获取和方言处理的抽象设计。提供接口契约的详细说明,包括方法签名、参数约束和异常处理。包含连接器生命周期管理的最佳实践和线程安全考虑。","parent_id":"e4bd9d6a-26b3-44a7-957d-46e0c9ba5cd7","progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-plugins/datavines-connector-mongodb/src/main/java/io/datavines/connector/plugin/MongodbConnector.java,datavines-connector/datavines-connector-plugins/datavines-connector-databend/src/main/java/io/datavines/connector/plugin/DatabendConnector.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Dialect.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java","gmt_create":"2025-12-25T23:43:22+08:00","gmt_modified":"2026-02-05T02:06:44.8075244+08:00","raw_data":"WikiEncrypted:55dsYIZBuRDY/jem5TMYGgaXw96crcgb4mvYxE6A8v+KwV3GjZ1L0EUBVa4TVkdqortSHSf6dC1KQdd8bbapHiFBtGQvQdBcE4XCJFGoSacmZ9vv2wzvMB/oeNYewVpmaTB1xQDL9ZZzUOIgBDNMUtMRy2VaXwmnGhqmhBWXJ/H2CJqs/4+NhmpJabYnhfH2zFurZQc43qTqshEz0ZN+j80+G/fFcaZbYb8ytl7AfoaVtU4pSMKoY0XtgLhEuulxk/Bd71IATwbO3153uePS9IpSxDfyRikxn70zd362lNakBxkRSekDPGhBW5i9SJDbzUceT6KGtfZF93AWIT4bJAW7D8GM7H8q3iT1A9Xhbf0sVgtLcaaaRc4GP77vh1jM/pNjpw4TVP/STq+qRAYUVQspQZBz0fnv7k3M7FAGipThK5J+emPf65yZv/eg5kEVNOGNqEUrXD9/YYahfI5624iCAX898I0JGCCi4hBnVDn8EX1aNiS2yqW1XXcWjJYqqzLteZHTNVHwrTxzvDoavFgsrr+pERSD0zOFvtEs+quIUX1jWihAMEX6QwRfa7wLcdmfVNbUcaVEMPkZRtL2yizoqaz66rWOJaRX7bS7kSc1vxmJMqQZ1JqCeePWqfUaUu3B4aw/B8VfiaGF/Qu01hiX7JMruIeJ3N8ywcpzuP4o02HGeABwfFqlA1TvzLYHjm7m2qkM8dO6oPa3P+kpKtphPFEIMbIklXRdXbOJzlF+zwsel9axrdDXH9xaCjrTbqgKwJd3MRNaBPwVHO0YHDX1skO/6Yf/gQKgV1R68efV0/53UGKCLQkJULx3h8pGK0NA3+OClS2UbE22HzZSueUfuyZk3SBf7St8dv3EzKyiugbaZ/K+qW3jawwbTmPSbtPeSz1rV16grjHBCzZZr9cpvcM1v0gMVsatf4WLUMWZJMxmXzk9FkdqcPZ0txvGzjt4nft0LL3C7R4RolV9rbtzyqb4LR5I/lWazgEoleg0WqEPKbCGf2+2iYFOjmJNgA3D2ucsFITuO7uEfr8L6Y43Z/CumgsMnPmmoseMKY4aDvuOdU2iHSekKzpZmbWlIk7estiDloGICLBR8jzULxFSxUTbnoz9C3I5tqDFw4cOkS++VJJm0dzbZQd1WVLJtfQC8YF9ZSzjlebg6kIRUrO24aO1aoIBI7l1fbYiQV14hybn91J5DDmV4B9AI6fuvcGAtv0ge1hg7np4JvAGq//NLTJKa/ZGmdw+KNbNAFrI5/THX2TNwMDriNPZEozLIjuIjn8YL1i+mCejcaB5J+pC84MKp0+VsyTXYjocsEFT32XAEh7adUCmR6BDv85REjQXybbdbxwH05tLiKOwOF7KVjG4Mp68SxvPTa0Pj+9D/4PhnegrECNnJKP1YMBez6uWC/vdPWp8XDznw0x2NhTOutGrSyiGyc7C72nA969CxcZMuvSBa+HQmbcevolGM2zR2d74pXxIBKyDp9fuTVZJr++xNo8sI8acpUQJuLmdHZIH1JtrRJM+7+C7RZVe13LbtJhmtxTkkq2TKV8LVwOwI6WWJVGqfCjs3NRyYn/XtnVQ3gArwAb6+A9TRJrEoLAhUfLBNH/bNI4V16/q0IK6ZF7DunyGvvwIrfOH5KVyB6SGf3fZzOJ6FYZAuwklwYJeLrqhNjZPbKf9L2cz6RmgWhgXosRTNTV4YT0BOiyIt/0AEJxmK+FaHI9KSqBlDJr8hXLEi6HbS3UlfVz5tS+Vao23KRDwjvbQmr99Rz7dclRGUaKE8bffVJMb81WUqBWT/N7WgUtJn1n3YPDUwQ==","layer_level":2},{"id":"8fd6b4b8-992a-4e91-84a3-3a347275a323","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"度量API接口","description":"metric-api","prompt":"创建datavines-metric模块的API接口文档。详细说明SqlMetric接口作为所有SQL度量规则的基础,定义度量执行、配置和结果处理的标准方法。阐述MetricValidator接口的验证逻辑和实现要求。解释MetricConstants中定义的常量和枚举类型在系统中的作用。描述MetricExecutionResult数据结构的设计和使用场景。提供接口继承关系图和典型实现示例,说明如何基于这些API构建新的度量规则。","parent_id":"706d1a2a-8449-48d8-8a21-58483495929a","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricConstants.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricExecutionResult.java","gmt_create":"2025-12-25T23:43:30+08:00","gmt_modified":"2025-12-26T00:40:09+08:00","raw_data":"WikiEncrypted:wqMZoWM7JzuUrLNEmTF3PFn9oPNqgGgmxZLpDGu1IaT26BIJzfOigz4GJ/hZr7bRPfXxAFRmI/acCqg/SjGsdkg8uatKlnho0pbdYyQpUw9eUIMz5y2NZM0N32uA2tR5Zyj3HcqmLjHj8MlA6Zug0i+yQPm5LgToZaEd3Bd5MNb+LBCO+KBUkK5qtyxGa3tcp5WNdTLfrXZL7FdYRtezP9EQvE+r0wanrxTIZRXjmU8HymisV+srKq2mnYevu5KKt6TJY8WncmTd8aHcG1ln3kyV04O0TYYYzTF/Vw3ca5yY0fkB9W/M1dV/X056BT5h0gmlW/sjU/3yD6FV27dB4nydkTFlmhRTpCgedeVTDKWXgQC/AU3w2ojGRrB0lvPnZGMoAcatU7if98YxUdW3MfA4h5kQmkO5bRMdg8sFwK3+/rQ0uYO5AQXFj1uNhvRZqC009OS3xTTQqFBHqNo9TsM1wOzyZE93AhBWpPFOs2YKmYIFkMNvAvwfive3bMsZS91mofe0ujMurX6ULGOrAmIY2PO5KkS0VlJhPqB1Zmmt7IVU37+qJqUNRFVIAYhAcppAEJrWrp/MjVbVEBVjoP/hG0uqABKuCQ6ptVSBd3N/oMSnMhhiQyn3BScIdeniO46J9YVtpmwpX8QxPsiVM35xKtoLS9NJ83NcnUf7SBgGpimgciv2YmfaLmCoAky668DH3p7cxP5JirdrqUSGehT96z4WxWIn8lPiB60/YbzZYR/E7gC9pBl8nMM5hk+yDFkpAV2TjTyzjT4NeJPmKJ/H+mpFzDXP+Z5a0HKvZ+L2tT+/0rdT7/QiOIUieiMGF0ijUczI7b7oVyAgN/8PLwR8TbcSt2aIx1Qhb5+KB9T+oFNMPFfsxXm7wrAQJGgjQYsd1JBqbOKcfX4JrbLAn8d0B7qRRtHpe+rIkkrNdcxP3ynJ+F/tHypNPFOb/fo0879cXz8K0Up5/nRMy1kg8oUBEwR08l9JCClOspqj+KUZ1587TNH6wn/NTfxxpS99DriFgrs+tUcn/8jfqb6vRolOGryl9uM5t8Kd2lk9HiL1cUnkU/B7bKK9uYPoWd3iYs82DN6pyiwVF7k70h97AYCWRlFLoHPfbnnF/Udazo3tDOwmEbUmHP6LxleEJHg3XLTmR+v7QaX0EzU7wfE1qZhri5RIzIIFXqVQez/6FZzDpCuQ6OIDNaW25lf9FFFvRLS4eFyYE21iLs5hX7xIoj5C8TmyrysEI/i/hopw4pTx8LNNY+6tUg+3t41WqWpsZEA467jnQWy+YW8bmEoYV20jMGO20ZrJsNB7iQ1iWUEpemF6j9Nt6i9iRL0xXjnzKoy1bRn18Hy979aE18j2wBwExwUxHc24BaGGNZSKxGECs1O1FSzkq932FLLrAzwRfAdxHJEFSztIqfDMm8nq6w==","layer_level":2},{"id":"49a4f37b-36ea-40fb-81e0-bc990641aa44","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"注册中心API","description":"registry-api","prompt":"开发datavines-registry模块API的详细文档。详细解释Registry接口的设计原理和核心方法,包括服务注册、服务发现、监听机制和分布式锁功能。阐述ConnectionListener和SubscribeListener接口的作用和使用场景。说明API如何支持多种注册中心实现的抽象。提供接口调用的代码示例和最佳实践,以及与其他模块的集成方式。","parent_id":"3d9880ab-c577-445c-bb52-b4ee5d0415a0","progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java,datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java,datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java","gmt_create":"2025-12-25T23:43:33+08:00","gmt_modified":"2025-12-26T00:40:43+08:00","raw_data":"WikiEncrypted:hvwFz+sIainc/WWi9rXmKXZ3k4X6taX2dQUQjByA2rUqnuZr3297xno6/NXmeWEKJglFTG2hF+88FrdJuK1BMaR7o5Le2dgBDtxyopaJSxyxWiYdoiiQsuXwVzQDT8eaAp8jgrdF3OU2WsBrHBqHYNMW8gNW3D/YyDaNVBGQE8kw0JXuMesqR95gRLPdIjyaL6G+q+NvB2kVvky0+NJ4Szw71ao8GApE4GRYkz3LLUzFslZms/XvmHmwO69XWwCEg4aOxWznhZ/YLq617e64RxxKS/OtfO7S8jcf0T4btiFgWdcfaUqJwBrTKX1sBjWM4ZJ8wyY0R/+ztAXzEFQiXeEaCbg5MHwHxklAW8IErQOWZPxos1ZMCIeldc4xFP4QOf06vxN31CylMewpr27N4li8qlut3N9g4IZdYkz7REuQb84SIEqOylKgcNPFUxRAT+Ju1O1KOMkHxDD+m2Y6sFuVD/ApOq/IP02N1vlk/PEqZseyv6/HuP4MdhuUlvoAVhvAVIGGZXs6EL8efmphGWR0epw408TkqKtQFv+DAkBq+zVu0pJJ8OmkT8FI9Jz/00YbZe/nb4nXAzpioSYsBl4CCg1mM6DkTKYdm+aYiuMFQvATWwmN70HlEIZ8ZuFMbW3P0a+O+zvPjuZZ3v3j2T6dYaveoIio5UiDcohWk7THI5HTgqiwLyxEWovY/5QuWRIsrHQGv5VMmJZ5VIRuFWFblZi7LZzdHyL+WRWyT8ytzdhqMF3zhs2e91cZ9Z6l0ptF+X5VuniOybd9txdsGJXaziEWXWkQbiDU/VN88yxk/0wBZCCkpXY/5hzajIHrl1BCFPkmRcRAvwRC69zE6pdYefHBoss5t962tIPwr04yaxlqtSgXHmpXbMu96eP7H+fQjZxcgpj3eX0EOOjLnkzC10AWOvFO57vjvYdJTOxAyLCPqkxtGLlJyHMyHVK1b7g/6EJeDzWVNMw7gcupvnBcfGZEZSSEbpiB3b0ZHQfDBQnhzqXQGEBjCflowZFWYcqkkPJpwcGxv1Wt6OYKMQ/6eQXAqbF/JXKIwrqSSuGkUatu4xPPJqkYwgU/8GI1JbfoUHrwrKIqfrTbpZq5gWhFx6HwLTkB2qLGyUgPfvQ8xND6ftsl2bQDiiRXERill+445RTq9j8Ta86Hv4EHSQeUnDyalzaTAVdlG4Mda0HfRplMedthBGNKJleFBvoq","layer_level":2},{"id":"6c3ef1c9-0be6-4b84-8244-1c98d62e3f18","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"通知核心","description":"notification-core","prompt":"创建datavines-notification核心模块的详细文档。解释NotificationManager作为通知系统的中枢,负责协调SLA事件处理和通知分发的职责。详细描述NotificationClient接口及其实现类NotificationClientImpl的设计,包括通知消息的构建、发送和结果反馈机制。分析通知系统的可靠性保障,包括异常处理、重试策略和性能优化。提供核心组件的配置参数说明和使用示例,阐述其与datavines-server模块的集成方式。","parent_id":"9b0e5495-2217-4011-bc46-1d550de3afd9","progress_status":"completed","dependent_files":"datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java,datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/NotificationClient.java,datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/client/impl/NotificationClientImpl.java","gmt_create":"2025-12-25T23:43:41+08:00","gmt_modified":"2025-12-26T00:41:09+08:00","raw_data":"WikiEncrypted:4+tXcquKioWk6hL5AaAVvZTmjZdcbuSI0p6YeKeP8lWgnr1UFlH2VAwIqCg9d9fBXfvJoHDvDRDuADGkKFAkTp0PuEQZYeDsrnY5+RgRFrX+UbHClSWz/Xbq8xm/hxhAOVy7ExMaUV3P0HAd9m/dxulmp/dl8j8hK6zsz4sQZpZZoZFbQT8w7vkZK05XJ1HPup1tZAk1g5XSVt0nuGUorDZu90Zq1ib87rp1TT4omrfPZXy+opBH/akEAqsPilFmfnubqEVPPw9+HzvFfCxpUSZmTOPLXt2uzDPxkCXPhtPEBomnfdASb2eevpgMaBiBZGf7UNuWWCZkVYP7NyaLxtiWmknKmnmcP1qEgE5AZw4UHz8KKaZ9oRrNm74tf06tqxUR/PS6LQOPJ4uE8qPYGSQqYTDXHa/C/vbmGNk2m3yLGD3jU101v1qhJCgtKwlElq6SYI0n5nvu6/swXPw+AXtQKHLvWHcjTr6a4MpACqryHbviAqyva/UPjfszyiJDNPPnw9SM1w7TAKX5nid7iWOrQm8/LhmF4CeuwQfCVhS0iAXZqH5QYiBpioPL0rk/zJ3HeuqgqR5COZCxR+FyQN3Lc4WUwggrVRm1CNPovxSIiDo8N6n+1pXl/MP23Ww3pmoZnkWrOWT4WdHSuYgwKOAiFxa2vM7g5572fDjylzlfJmbQF/NMzWgycKOwJd30S9yAxtFcHE1i81ed20BHQYLdhFMJeD5MfbI3qugtpcQiY6Qh4UcbdSaU1CHH6Umic7KHJwdLOEdCvjT00IR5glGp1jOr8qPJX67pQW41U4yrPXn/7lwfFvgjvnrNsz5VafCifCUFp1LX4+xRjAejVTnin2eXZB3+MhhAKbTblRHu5ILYKwN1cUoPQmvcC37uiC+e4NXaSPzldhrQAEgHia/af51QwSWaokICtLJzjlzc8TOU6gMuCfGnvQk5TKEb+fBgxVj65d5ZvyH/UV5JoQVAx8BOU0e3R0x7mtpbq+g9A7Ip8tLdiHp6jjKFcr51hQvH4ZlO0Peeyil5VHgORkA2auw0sW25xDyp/YUTvi5kO7iNNxtxeU7GRQvVlt+yBScG6MZlYpa0Yf+EmbnsFwC85G77fh1FMHG3C4IVYERyxtZ3SuR+L0mFE6lSw4Rl4Dk2zSS+dQeelO2AzXuoS3VLivsiqD9WS5mUdkMz3rjiDJtYkrNL4La/oWlc+bLflUQHD9eWFn3ITBTKKoKN/1NHP51mYOfqGsawejmdpSb8qkH7pjUt8Qeq/PpFpriJk1nW5d1Nk2/Tn14Z8Poi74rXMUIWLQB+PI/lQHZXpqkWBTsYlOZJypcD8lJY8O9M23dfcVwmGa/43vITMSU+3oV4MgqN5HvQIWp3kx7TrGH324ff1JV6HQgtRM3Jtc/vLVKZrolWqUIX1zRmL/X1Q1pqOTCR7I98KvQEIsI5rmSn2q8vj6483GVlc2dp5qgbaavJjGTui8ZitIicGdRE3Q==","layer_level":2},{"id":"8812d4e3-553c-40ce-990b-af96b66c9c09","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务管理API","description":"job-management-api","prompt":"创建任务管理API的详细文档,全面记录与质量检查任务生命周期管理相关的RESTful接口。详细描述创建、更新、删除、查询和克隆质量检查任务的API端点,包括HTTP方法、URL路径、请求参数和请求体结构。文档化任务配置的完整JSON结构,涵盖数据源选择、检查规则配置、预期值设置、通知策略等核心字段。提供不同类型任务(单表检查、跨表检查、数据画像等)的配置示例和请求体模板。解释任务克隆、批量操作等高级功能的API使用方法,包括请求格式和响应处理。包含任务状态转换的详细说明和相应的API调用方式,以及常见错误码和解决方案。","parent_id":"13e13644-8e2f-4f5f-aa08-89d3878d5113","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-server/src/main/java/io/datavines/server/api/dto/job/JobCreate.java,datavines-server/src/main/java/io/datavines/server/api/dto/job/JobUpdate.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobVO.java","gmt_create":"2025-12-25T23:43:52+08:00","gmt_modified":"2025-12-26T00:41:52+08:00","raw_data":"WikiEncrypted:yegyDk1wqjjugZAqlZ2yNm/RcOdiBq1qyG4dLY0d7AcKohq0oYhQD0DuiG+z/1pQu79FMSiGRBLZHt5M9jSu/LFkpuc3saPv/LNX5X3q4EQ11hHCpNDUU4IDygsJU0PWnGeBccC+5v5WXB9LER3+5fFxBV45QWjAQDurp6b1P/V9m9vyfzIlm+2EGoBLAxRvz/wFj4JfriBLMAgAMeciAbXaJC67Ckc5ozA9qDvKtwZnhNiuN0iuoCcpCLeGOFw0wBO08xVv8846+C6JF4nBj6StoqaOntUpXFaMDRuIBeotdhdgUEcAL9OrCMR3M0KPXHraKZBWpMJZ6i2OZnjWk93bA9nOTrX9YKOwGPccKFZPqmlIbKniP7LLcvtM789Ezz47sEEPFE/DyCX64RlB02n0ElPBmX5jdcrq/hXOHnzd463qq8h3QKP1huoer8dRR8980ZcXKyLxFrK3ao263X6J4VwyX/eWNQraC+U823Vz3nob0a6ZaFy7q/bSiLK66XddNrB8ZXBMaPN74oA27mVVZcQptgGMqXXLntupxATACnjk5O3958kP2dzpu8m0+XO9LPWD9S4JmXfMv4ffXbMl0u5tkKD80SQf/t7Ho3gKdC9sNNNyKZsJMd9jXw+ixyBa9hgNHs8A4LzLrskbZmGOvhY1SpwQuIx/QewAiMeuZm/VmkuQ16HTSdJtiW9FjogLTu+GLhUAJMhLq94JaFRi7O3bf2HWj5+Uvd7CL0n5tbPMkEjP6/fan6PUHRRuHslbn0A9mz7/PxytmMqvbP66Xcmv0glAfkzAT5e9IQKWQfZMCUr+eC5I08lX735Q9s8gjEvED6cPI0dH6eOxjCxrDaxQExblMkc64OVdk4TkEfXpLs8LZj8mIm8CpopCa7V1JwVUYserdNEcR1ydt3WRvrnttWVvgUVkuoGgX4gsKVxLydbiRMa9CcHlfkGYbZZOVFYi762Sq3T9E+NAfXVmruyF/oyqmmDCFqeLVHl2/dxSsbEaFIhQsFHAeyks8DlquXpEkRDljgq/zLhFw4N0dtF21+KgxVF2Z7IEqkSxYw4llS3aMlp0hD0vNWKSruABilHlrzl/9qZ2s5NrVbw1J5fSxq3Fxl4s+eHab8DTo+u+XG/Pj+7YvIekYdeMpcZoii7VGn62j0Mg4AwzNEiJSc3dtAANzQ540mTdCkBlvNAaadDmwiwgHQSifW17ect8fgQgq/NGLPMSIHmJoimtORyeY5I+Cr/4b07Q3NEAw0bNaN/PdgyXbVa5Vb/MvpugUiqRLjofS9KTyfG0PnXQ5XsGlIX4REmnK7HmEsLWJtcxvj2UT7b02E7eL8rg5xpOEqd60c5T9QnUE5doRrq73ysHEwUsfdXxlyBm2wDkoWjdBRGdl65mfTc6OtZBa+NMkFAd1QEEuVOZxmKWHDoehy8jrBWXK8EJ2cuCzpbHdjRFN/jIy9QPL3BefGo4VgV4+egpJp/91YTezAEP4kQTVNIVIwwGmLXYffeNJxaKicorgKLKIw/Z9iDzYDfoaZNEeR1uFLnO3jKFkrl5igoEMaG3KAh6+/qpNfPYuK0KyZpc8rUEnbOsQ8voaUM74hM1NsugX+pae0uQfdFQTtbyHi6D7mmVi1r8TdQj2Hr29jUnnC+q+a7JzeF/h23rmrgBnOPJqCdw3Ksd7peU0C92b1lG0IZAlIfW6aYnbaU=","layer_level":2},{"id":"31124011-bb2c-4479-bbc6-005303e34f2a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"前端架构设计","description":"ui-architecture","prompt":"创建datavines-ui前端架构的详细文档。解释基于React+Ant Design的组件化架构设计,包括路由管理(react-router)、状态管理(Redux)和HTTP请求封装(axios)。详细描述应用启动流程、主题定制方案和国际化实现。分析代码组织结构和模块依赖关系。提供架构决策背后的考量,如选择Redux而非Context API的原因。包含性能优化策略如代码分割和懒加载的实现。","parent_id":"f6fd9d61-f5fe-4cee-a269-b29ba2583618","progress_status":"completed","dependent_files":"datavines-ui/src/locale/en_US.ts,datavines-ui/src/locale/zh_CN.ts,datavines-ui/src/App/index.tsx,datavines-ui/src/router/index.tsx,datavines-ui/src/store/index.ts,datavines-ui/src/http/index.ts,datavines-ui/src/theme/index.tsx","gmt_create":"2025-12-25T23:43:54+08:00","gmt_modified":"2026-02-05T02:04:47.9892261+08:00","raw_data":"WikiEncrypted:caZUAHH9Plb/hKq4968GAn0TWo20igRFEXdgjam0lcacGBbWIQ79feMtmUr40Zv/HxkaiLXt21C7DFpA5y0iNrClNe9frXdD7KZvK58RJagojnDksmc37DlfWx1AQWLxc0879KziiwORtRHpYCnDX1b77F6brA6ggjlLoC/vSoU4tY97CjWIf9wf4aVAUFzU/nfauUjduzAdglluq8HWoF10Qku5WCzddAyybJZg/KW9Sg2GTBtppjODPf0l/EzSyldXCsNFIOsfWGsimvDfFD8iIPWypGndmaPNfsGH58XblZTlEKtbSETu5r6MVf5HpfGk9OfY/0pxEWFnV3cO5PXTQGQ5v+TQ2XPM2L/kv4COxFfBCKpqI9fPBz5QI5E4Vwl5TZRb/DaPsI5ZUZFRoNMXXe6MAdWRQK0TtQ4tP2AZWC/3PAnicV5wS9LC+zH0cwQIrdWqAAFkV/1TtxL0zrl11/u3UoUdFQGuXfTrG/dIqzICtj5WorUZi+rLXEoZU6KI+2BfzyIf+P0RtTgHacQ7D64QrBmj6C/TPybSRPDZLDQLFSWQGFJdVuPMJmgsLljGzzdWu+Cmg/RoY7e0NHfi2yQCOJTlIh3D+8r+A/XqzrPv9kn6+BMN4UgemZ2yxTuIm/bgr91F49tJ0LgU/os8Wbhok8UdrBNBMGle/3kDVjlz/StVfcrIUzPXLmx5lo6B/oqPKuhDto1WIxBJhpykjglGDMmZFhRK9nYOZpC434FiO5ERT5gUmjh1yvDf7uiHx6Wfh7SHW8ddWyxzV1tl6AGzxT8F/9bK1m7sgjMQ5LzM0xNcDk6QnPKg0B1PQDb0TZAhVbu38Cio43I/el+UMuOjwaIPgGUjW+hRTSLaLbtzQIKN5ozPAoBB9Q+Yd23+/R7sFsRH3oE/V5syla214r0pxTtsvVk+r2jjqjaETaDOHGw0ASGkAXUk1BBZpxAMDfcSgJWs5g/YcVTmoPvmawRv8OgUjcxo9Bp2ctHbYDecULZsH7LR+GoBgw7O5pj+7XS9UZqP5qEQxFo6EUFolqvVsKOdO6V+lzjs+mQWFxHhJ8BWlNTGq3iNwd3n0awEzMSvkAmi5IU88eheDdOtDHtFQGEswhxf9xZnhNBxcbl7WPri55Q4DQacOZ92YmidtEkU1a1uTVLZLLgdP9sZ0g+Ka+oyTJJkLXjC3SQ=","layer_level":2},{"id":"b35620b5-0643-4c61-b8b9-da5347435165","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据源表 (data_source)","description":"data-source-table","prompt":"详细文档化data_source表的结构。提供完整的字段列表,包括字段名、数据类型、是否可空、默认值和字段说明。解释每个字段的业务含义,如name字段表示数据源名称,type字段表示数据源类型(如MySQL、PostgreSQL等)。说明表的设计考虑,如使用JSON格式存储连接参数,使用加密字段存储敏感信息。文档化表的索引和约束,解释其在系统中的角色,即作为所有数据质量检查任务的数据来源配置中心。","parent_id":"3c7fa525-a12b-4451-8146-b1bcfafe2f1e","progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java","gmt_create":"2025-12-25T23:43:58+08:00","gmt_modified":"2025-12-26T00:44:15+08:00","raw_data":"WikiEncrypted:yP6vl3GzzNMVOI7+ToNUFWUXIeYqYbuM85xhj67G5HCCskYZi8l+980NGbIj6jsjDIthh/fIBkZZZDiJMdB3YFBOb2IqmKFsQXZ5EGRH+2xfQ0PNmCZu+e6ZVfShUhJZZIdYmeLM5FEw2azFCP0irhcPbHmSP9cALVHw3eb5gSg3eMLUVjhxVsuc4PpFnS9ikdcndJ18/fq+c4TQKI8e9rGGJZylUs3lBsl6cA+ahDKL6o/OecZDgn1RB2/yD2qmYrEOSuEZc13xMV6AwfFADsCb8+RqJ60XHkldbem6vcIF4+AaCWMtFmd/4x5TSwgBEw64EwZJzNoMk/QL+5A1FPfEq4Fzwno9oo1wDkZI/H3JgXyiSyQO2qUMq+5t32TLvjukabiooJ3eY2OHi/OgZ1x4XfPr1xTSr5CS0ABlQMwGDapqeS3YBlbXWMbYzn5S3Md4USjNvyP8edb4ucmODxHU/azQxW9WF91LQSvFILqpJeWUBcUmYU9jZqeamcRlIw/h704k1dH4ydLWqN4c9ksn2RYOKwppKeAjg5Yp0fHa8U22+yG1D+bwUmGhajeUJnki+m/SawWC+8r/7riFm9fUpYbAfzQfd9Jt+kDrYFs19YNcISdblmZPoi1A0q3tNLFanTTkf25OouG2yaS2hXMXjSN4jred+9keR6XAHOyR3e78BRAuCntf8S/AcL42IgIKFMnkaDMLSF98JGh631MNJlNkYzado2l36XaqukIj+FDSsxoYpdjd8L1stiHVDRXzG8ttsME13Z9IG5Sx13SsopAbLVqF5DQ/eQMu5YDwmtnhDPNqZAtamFxwrmxPDUVkSopaME7megnUH89th+8L2K8tHbb1avdgIo+RAWcEsUQqiy6FvJ28q1vFLtck/QOqu5mCnReiOw7BPBpniJIXnjkD8STx5rmIyFFalp/ALPvEHlVBUQGzi+9UEVmw/hDV3NxEdJLmhSna2R6F5uAf1LUjHcKOPvxdd7YcfFNVfrrmQSd4inA3HQZnmHnAlwG8XySd2CiTEVa9kSwwcVrdrSJ9lcZcAIWVV4yXkaGGFVMFGa59jsKY/wwboA0rOooD33vZ+Fb0V2wbioU0gey+2fhsTc1gJV+7PkaSL37D4cacpdx2UT62FqZxsc1QE+M5bMdNVuNtOItMmHqGsg==","layer_level":2},{"id":"2cc32935-3372-4d39-966f-a179c9b39236","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"实体定义","description":"entity-definition","prompt":"开发实体定义功能文档,详细解释CatalogEntityDefinition实体的结构和字段含义,包括实体名称、描述、类型等属性。说明如何通过API创建、更新和删除数据实体定义,提供具体的请求示例和响应格式。阐述实体定义的验证规则和约束条件,如命名规范、必填字段等。描述实体定义与数据源、表结构的映射关系。解释实体定义的版本管理机制和变更审计功能。提供最佳实践建议,如如何合理设计实体分类体系。解决常见问题,如定义冲突、字段类型不匹配等。","parent_id":"493d76ff-0c76-4864-9a2e-0a1aad23f133","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityDefinition.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityDefinitionServiceImpl.java,datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java","gmt_create":"2025-12-25T23:44:08+08:00","gmt_modified":"2025-12-26T01:29:37+08:00","raw_data":"WikiEncrypted:WnER6MhWFG6N6U3R1m3zi7GoeLJl08fVNgp5TFqADEUcunEDsdvVXV6xAIoDaUhF4rmr3pF0dZQNbBWFJuSvvR7lUeJzRvYU8ymNjU0NOvPLWXdCEuKLwWETkuBLFQkKEY7WHazVZHU31VKJXDzR5OlPJ8AU3k0RhA+CHe3HwiOwQJNKSF/2S5Eg/oFxBdXVE3Dq6u6t6OZGrx7UIoPGS7ONV45bQTGh/pEDywM1g3CBHKVtdfznhfQ0mbFxN4X2xi7f5R6hBUzgCznj5AbFOxlFAwHfWiSX24wtlvDej04oM+nNOwRJAhxsXzXvZIwnucXIZBoWI2Xf6Ufltu+75eCq/9m8193VliWFUkj4iwKX/YrRl9ZQAx/R7HrAspUm5TdZ+xHTRkiHxRzx4LU6bq5PEZJ49V1tsqHYCG/xHyfyGaXI5TBI+ejeaMSn1MtTBaWU3NvJx9uI3mjvJx1V4LA7kWf25Yh7LNfkM/gvKbrcnE6fk0ITw/EvKaYKmsEx9CLLHt3C5WOHKB9oMbvyf/OoPMmbLDn9MTlwdnFdlPEkkzCTLGVKBqSCbKiSojZcXa4laGQNjyO472dHygOVVNpAw941vede7JrdSA78AzBe0VsLAB9vgLWZQHPOYtCCBvVmvuI2XFrw8vYFtMB03GPBcJ1HKv9wXbyjZeNeKGmISHUtCvYzgxFzr67EcR6mQAYWhvHfSRXhEo8/tqAZusiz3VURynD8nJUs1l0pEAv+sMOppBH/RWM/oYhUOPKZ98Eh55zGP8BUPxTKdvfKRnZQG7W7xW2hBVFiLg/F3dt6mmKTIiqxCGJEErP6hYz4SEFm82ulCT3sVDArj1p6FUXu6Zm3+aZCirPZDq4I+0dfSMc/7pPFLQgMjcaq0GqkJtvDtrt2hikuHyNgy3n180aJtY/rHWehaT1mKK0YSJiVPu0yhS5mgl1EhVXl7VOBP7/q9TUi8rvhYj5k3H3rL59TFKyLGO35yGWosT3v9YWiU/tBo++zAk47lcb9l4oZl6g16b3ikLZ+dcxzTAoPc/ZitOctE0U4I+pEUAiWxbXiOySCN3ETSxoL2J2YZzyZBScCp7zhTV3oq/UO6aXAyRgMY7pONBLLlW5eX9X4/9wIZrbOHzrTe9Ib1E293a1yRTP91+hcApOBSxgLy4mFPfQX483NA05iRJ5zvmgLfLppTn39MFZ9ca0sTtN4vrOP7UvNvtCQ1QccU3yRjZYJugsm9Uv2+KVuAQZYL4FAiHhBnn+bACHCnilnFajEtbs7crPemL3LUhfIDHcw1cjjrPPgHaEzgqKpqLFqsrFk3x7EWQSaTFlyMtDI4mMMCFbtucWkB1K7A1aMkLuYa4kT4r+M3IFte8mlFDJn8879ilnMczr2dJo0jT9dGTWZkwrr2H/oNLGDJCuZwVTXmtIHThfMxPyZrDoSWZG+MQW7Hcxd7amaST2FEmklHymwEWMx14KYyGMIXmwqgWe42IHZkwCapFovtZmlHl73Z1XJKJfclg12jKDyEGAsSrVHgCzy","layer_level":3},{"id":"3d773a1a-5048-4229-8e0c-730b504662ff","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"变更检测","description":"change-detection","prompt":"开发变更检测功能文档,详细解释DataVines中元数据变更检测的实现机制。描述元数据自动采集的调度架构,包括Quartz定时任务的配置和执行流程。阐述CatalogMetaDataFetchExecutor如何连接不同数据源并获取最新的元数据信息。说明变更检测算法的工作原理,如何通过对比当前元数据与历史快照来识别新增、修改、删除等不同类型的变更。提供性能优化建议,如增量采集策略和采样频率配置。解决常见问题,如变更检测延迟、数据源连接超时等。","parent_id":"586fb977-73cd-4d21-81a4-ecfb619947f0","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutor.java,datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java","gmt_create":"2025-12-25T23:44:09+08:00","gmt_modified":"2025-12-26T01:30:56+08:00","raw_data":"WikiEncrypted:MTGOV8yMPpR4TI1lgrJ8xECOg5KAtL+hPi/4Y6WZg8BjW6fOLY6xb0CIzd+GJof5rXtQyeUhDhhiDeWwnd3OmZY5pTBbD8161GdMKXIolFcPMQUvykqaG+bJHYq6R258kHUv57OXd5fbBlbfJ2dCL+tdWTAmRSYI4zV3Z3ctVI51LqMjDgKRWN6sl/iNm3e8JHF08u1vYaHtAv/p8caV5OBLxCrswfIgVQdr0wHMgGt0kCXvaI7EH/5qtH6d/3tvUKinFfGC+XgDVGAlHdm8fvxdstWHJ3OXduQZxj2aV5t8Bfjzjqe6UIqdf/vTOiTKWvYsL0gF3I3Jn1lfpLIGP1MDSEFlKlO77PoaKpJDAoS72szgT1HIy/JylTciJcvqxnU4lUt52HZ2gtz76b8zrWHwx4pZVgiLzrGTByRO1DOG1swo6TF63uj/dDgitpaugeztcLDEMsihMOJFYOT96eNjEU5s62oPpvQWFZ/wj7Qw7dORi6Acjslvg8ck37XXhtrxg37rivgunHL99Gj3ZrWvhF6hKZttZ7CgDs1ClG1MsCvBsT82cuGRs29P3yVvg8RxB5BF2aAoYs41EU8v1DsDG2Wyqd2QRMcqGxLoEYg/7vDMhuklSwiqZVUGAWCIARm6QcvEDejARTbe1nB/8TPkH0i4kxTXbkUj9faijZ+e2Yvnl0CsgBUm2ILRdQjPkfuOw+Mk/9lY4T1p1+2adDxbutQlIiJpQetariYZZMtQx9q6S8Id3V4LzXjmvnnIQpGryMjWT/grC3SpiSEkYal4a2SZUrhZZDLlDfeJCCTp1qKBrZf3fbB2bOEMbHOKFh8Xrnenpu8M0sabsjXNO1BllTNOquFn32tBKfBuenw/Clref5FC965V2ntSg4Jf5E5zFj1KTw+RpHndncYO0YFFayE8vZWwJEfGMsU8n6bx+cljjarutL3Rk2Bhq+2KEek7myQ9M/3P/kBSGEDva3eNA6U5/9I6ck/cERbrQKA9WvNPbxENHU9ZgJu/xtKcMP/Iimiwa0LW7pG6IXLBtVCSrQgE6VnVR8m6hBHRcvdzNo9+Vesk5w0i0S48er3qKVfZqeTqC7PQu2QRghL2KAbzCu5uo/tGgfDon3vMsxPW6yuHwQpQhP1ugCIQ7rmCXWDk0hFA2Hr0vFxNzYGysMR2NmCWsv5RV6AKJTm+Hl88k80McV5J1VeRHrUXCQU9+03Pt2dQJq9DALNLstcPZHcejG1C/ycqqBALpUCdse4phu4uhsd8qFVouC+Hc4bBPtz451cW2lKM05LrXzGjuY6SNR57HtXsYwTu9v+z3tqhcBlpyDBFMo5/FkrSBb6PSxlnNPv+1+7POImb282my6yEbTaZc8dfABoaXqqcP1u6ryFmSnAtqC1X5/J1hzugA0p+6C4vIkzE/cRvrA1rwmQdgUS0RJrHUwDq9d2BldGXFsS5CgHTNZ8D5H8aJs7s","layer_level":3},{"id":"9fc3338a-7ffe-4e89-9746-58390e1d7b4b","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"基础配置","description":"server-basic-configuration","prompt":"创建DataVines服务器基础配置文档,详细说明application.yaml中的核心配置项。包括server.port(服务器端口)、spring.application.name(应用名称)、server.servlet.context-path(上下文路径)等基本配置。解释每个配置项的作用、可选值和默认值,提供配置示例。说明如何根据部署环境(开发、测试、生产)调整这些基础配置,以及配置文件的加载顺序和优先级机制。","parent_id":"d6d39194-b46b-450a-9e23-15374a060630","progress_status":"completed","dependent_files":"datavines-server/src/main/resources/application.yaml,datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java","gmt_create":"2025-12-25T23:44:13+08:00","gmt_modified":"2025-12-26T00:44:02+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjN/+yV0/ZdHFo6MbmumGU8nuawR/jyiV/QI2LwMxGkQa0aslI320MkYJRuP1umuKN6w6NV90Zr80Sqv6Kc11IC5nTpT7OMwVyQgMV5fEF6rf3xQe+DhpPrVkEfXYjrmVcN1lAbJ+VolQ5IqXGadKmNtixffZo70cukpt4ZEJeNEBkfPoRmLZGUVEmju03I5lxusjdOS5IAzadixry8gVwa52505rlnSGSN2jCzZ536ArITpvO3USNH+rdWJCoyfbFa1bMlqB01wD21M3VulR4TY/3bbxxVIVRe0ds6953jrmmz78zw/w4gIaAGlDRutG9LEcH7nF5HPCWAdlkp5PUUguec0WQ+UQ4QM05oD+BiZMI/YETr24p0zkLVVdfHj/lwR30xgkzL2P6mfh9l150nIXtxAWjXlaNwhukz0HQNH5LntAWx8sLUwvoweROEwglUVIReZ1dpklgzMCnzYbtQvb3GLsvqGgyHm1bQdaInhf/neTUiZ0StF64l6ob1/aRv+fFDlLEo6ZJMYv38Eoy31PhdGdVBdI8uzvHJN2e5IwC6ZG3O2e4wJvlipZu0mhpqXZeK859VSUD36bcM61bzXRajqjCSHv88902wuiiOXRVKVTC169/JvLQIi/paZVJd0qSj3Bg1uzNExiE1CW9HntWbYsTYucoBTh5HYmz39JJXTf+BNBwoYzEnj89SqMYBzj+4K0IZ7fI2+bH+D7TrwrrG3aHQ2uBXSkpXWO+UVnrId/Yj+nCuc+V/4sOsnQhd0KzLNFjeP2e+41NPR6bzjxIpFZLUMl5IPra19YkjbRr+Lx/uypVLTiOdSCwtrAAqS7jVq1rZkFquczQhd8BRYhrqjRpBqAzvfp7017N7lyuJrb9qngoxFw90s3OqFnDxBGXD/0fQnThil9eGqTv2I55HqqkvlPOdZyshePERfFC4OUYt9DpxbkLYcDQw20qtCmnqjxCq0C/WAvqGiWeGHSa59caL+Ls63Duz6rhetuxo8ky7dh2owikZrlYR8T9JZKQfLFcYX0FL/LK2e2pn2DpKaR7apcQmnQqmeMOQbaUI2zNBm36+b3AYkL+gb0zHz6RxWEDOiqf9j8COISpRQ=","layer_level":2},{"id":"8e1382cd-548b-4cf3-a8a3-e29a4289097d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据库连接配置","description":"database-connection-configuration","prompt":"创建数据库连接配置文档,详细说明DataVines的数据库连接配置方法。解释application.yaml中数据源配置项的含义,包括JDBC URL、用户名、密码、驱动类等。描述如何配置连接池参数如最大连接数、最小连接数、连接超时时间等。说明支持的数据库类型(MySQL等)及其特定配置要求。提供主从数据库配置示例和多数据源配置方案。包含连接测试方法和故障排查指南。","parent_id":"74203214-3316-43ce-b2bb-545d7e140a7e","progress_status":"completed","dependent_files":"datavines-server/src/main/resources/application.yaml,datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java,datavines-common/src/main/resources/common.properties","gmt_create":"2025-12-25T23:44:21+08:00","gmt_modified":"2025-12-26T00:43:55+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkEnWOMwf13PJF0o3r14jnHWymU3Hc1Z3rv8fAjNuADqZPyu+b4MrYeWzwIUh9ADJV/WIYuaiHAF0yyqb1f1mEMz2sFU+VzajeCMWE0r3HKvjtFjdBQazgigFc162ji8vou5I9ZDYBNB7fEuQ4HW7vMmeAPjbOSKjJXKKqej3NnTJaaSyN6QPx4Tf1LZtII7+SRPisccDzyHegofNknwt3rOIycnexMl/0Sl2jf2c/khKa4pTuTJpp0rqLeZroal8IkuczoXQaBQJuxfN4I5wZBy5t6KNjGfZrtatKjCnd9oyx7WY6DqAZkjxbQavSPBzDpLd56lr10JqpuEUQa0ufWNDVYjKlUBWVGpm0Die9R27u7Xkxw4nCZF/EI6a84mhWdTr333OmtPY2kbZGD4kjSjM0rvfHk+VY7Qdurvbyi/ANOW9KL6alWVwF26jZQlSqwdY5/nDN+TY5zCBCrrFK1vK9ubnqz2+UY7fNfCdcN7AxmlNS68pGtuE0brUFE6jyTJGMqCJnLAsjCBTrAmtNdDGnOVjyi8REbchteSC5RAXH70nxZHftru7NrYC7S/fFTmjbZ9Lm5oEN66HNSt56ZYPKzsGCdERbSyJhypgwpJVZwpE/BAsF15V8IhaXoW3s9DMDHRhJI/9VzsGMkSU0AZ5MVtwzdP9p0jp2pI5/grsD8SsoEqCfmD86o6hITuAL7oTLF0HAreBt5LNj3ODgSo85/XY2D5lqE4IyGsDH8AcnezmtAI2+8wsw96/JeWfxrE5urUOpQ5yl8+BDIaKHGg6OaLDfXNE47skbyFIHFv+orQUNKFxUFEBgA3hNGE/SxZDnNX/jRCOEyNO8wB08RcuAWkB0SqRXMenUR0kDcWp+UNVJ34VTC9NIJHTnCnijXZ2eWF8a7UP+ncZYkmON9mCpI5i9ELbDiYLIdRukaiKaQlBxDtzWGiCdvizYR+rUWB5lQT89ug124wMnFDgvNLPIv2SFVspBOPnStzx2eGj8K4n57ZGbCN3jVGrcVy5JpTPdH1xygvJP7S7LnB6E7fscNdYCUlAmRf3RXNqO3hfCLDCRa4DOvGBHbjLYzMyCDx8fnu+t1AyZpmplTF0OUFkQE/pZfA6fniZBRfZf1/DUCTp8salRBq8wCcZWAAgC6EOzSelvVVbYeX1nx5s3vQnDhFQFhytd2LCNJElQZNgJUVp6pdDBpTrZ8V7o9NvH1CGqyHLjC5Rj0fF/r4WbSbcZ+I0IJz6M2crutX8tY1e+pmhm9te9zDxALV5zjkssw==","layer_level":2},{"id":"00a54051-ad41-4d82-b7af-499fa8e67486","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"钉钉配置","description":"dingtalk-configuration","prompt":"创建钉钉通知配置文档,详细说明如何在DataVines中配置钉钉通知渠道。包括钉钉机器人Webhook URL的获取与配置、安全验证方式(加签、IP白名单等)的设置、消息模板的自定义、通知分组策略。提供钉钉通知的测试方法和故障排查指南。解释DingTalkSlasHandlerPlugin的实现机制和扩展点,以及如何通过代码自定义钉钉消息格式。","parent_id":"8938d0ac-a871-4818-9b4d-dcba6e588233","progress_status":"completed","dependent_files":"datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java,datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSender.java,datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/entity/NotificationConfig.java","gmt_create":"2025-12-25T23:44:31+08:00","gmt_modified":"2025-12-26T00:45:25+08:00","raw_data":"WikiEncrypted:MclloEy4bDTraaKmsUkqfPJV6A/zsFo9dljDdfsNMP6DUobqF/J0o37Nhd7rRoNWyl+6EE697yqAKO4PfSsuQCgTpiQIHmT/2EaKb+TOMpwoX60dJUdqWdm7W0OdVkXMpFVnswGcqYZqjwA/PrXYLfKVlwe1jU4ouNw29s0v7s8qxM+HORSL+R/gyJpnBmOp6SazAYbVS9sssehBOHv5tAXisrja7DV0syZiAkErIBCphIxZnmegxzds9VTZBnFcRLfWF4T97U4p++jFoybddaXkUo+sLvRtjoDFGk75SJ900agmkWCrs4uf2nzZIuERARsgfaNk17I38CR7Ld2mMBZinKmK/JA3IOen92vks9Pg0c5quasCSmg5BLSTDCzInkNNzvO7n9HVvQhWvNGitCM8Lx5KDdx2M6DGm5xsnEVbSMcAJUWE4wQMu8HUwnx1qIOKWmTukxu7OhqLbD0jtHinunQ+1xzuhP4g9FSOX5045Ej0dwU/SNm/jSEMn7eOeqnnhI29+gP0W+HYRCDMWy1UdDsuyl3vGxlq251Onl0YQ6fFSodacmZ9lMch79cpGzs+/Hc6Vt6QW3+mQDCp6UDlXoUhDnWbt0ErorbBqJRvU3u+0BdQszkeGxI+KxfC4iqMSv6OW7TrrkquRnyrbXYbRRlCG91/dhw+LfCpTS68QY18jAWK6/EtM6dC61zToUyKBT5LpoUPXWIpuLpGSV0qgc3z5Q/vattugfMwF/52zKkS8XGrfHXlWdkwKvmvglnm85tHpGfZGxdXmlYPJxrPjN/kC/4fkLX/HPs/DkKZvQxbKnin4yxXnjUHBefC97ZkQQ4XyEFDg4w4LN0X7s4ESKbThFkNnwDaj0WIxpBJhGJbrdmq7dI8EHKrtgj/Au0nxvy8LZubDhcV03RnVsxhlI4fVcU3xZp2cpm+dFBd6E9S1j52x6BWXyJGl2+TnIS3kVYMuiPcr66C1xPk92WXSNtbtYBwBGNFM8jmpzepSwM742ijO3COFP8Y0DVAxtM+96JR00xnOAV7zbV5jBZE450+0PdrPpQvYfjkk23hH9+vPF+EI6e2yXA/kFJlgeHyfwt4Oy7sFAmDrHFyld+kSOel61A4bjtKHhV45tC4KR/3jUj3w29olG7NIMiCS7VSb7OplqzptF07D+sjkjCnX8KQ70zuRjeyPCmzfz6eFaCfZXkfwMJVAAuP9JKVnNBIhqCmfh9mLIllCc3HJzQ3Ft4QOArKnPJ5a3yWKhtl3/VjuOgG4P4JsWcQTl3HB5ThlL8dUC8GDxYsKYgEIopY/VeimjWBSspvETj+56bqDi1SlktCnjvdgcpFbMdKV/du+W769O9Mc9OvToDacXerDOE32xZYVNac9JyIqhGIjEPhvLMgGyEhA39+ogCAY1KyaPe1irjfT+YYEfQtEznGWqcvk9qPb4Y99ykZw3aa/f/FHjtP6pY4B3pusbjNG9EgcNzK1zRuwBGhN6V4GA==","layer_level":2},{"id":"70134ca9-ea35-47db-9e54-9ee96c02f6c0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"本地执行配置","description":"local-execution-configuration","prompt":"开发本地执行配置文档,详细说明DataVines本地执行模式的配置方法。包括本地执行环境的初始化参数、JVM配置、内存管理、线程池设置等。解释BaseLocalConfigurationBuilder类如何构建本地执行配置,以及LocalEngineExecutor如何处理本地任务执行。提供本地执行模式的适用场景、性能特点和配置最佳实践,以及如何调试本地执行任务。","parent_id":"69630b5e-3d0e-49f6-884e-8e9fe153a0ff","progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/BaseLocalConfigurationBuilder.java,datavines-engine/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java,datavines-engine/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java","gmt_create":"2025-12-25T23:44:33+08:00","gmt_modified":"2025-12-26T00:45:44+08:00","raw_data":"WikiEncrypted:XMvsRjFEcSrjMOAT9RAdmxRWkrgT0yzhACra5r8eiaPo7bqw7UUtSJjKxXrvo1HGRSsXpIF2gVSbpNHlni9bP+vqmNGu09XkkNZNYyD5tqBFCMjrVatYBY83MncMcMx0X36tNfFz8adWh3imt5jPELQoC1xKhlepyDQMHm2tEsf/qfupIkN/gNwqhaYAYCSzIIKfJrEC7IFX7zVFWoSBwmaXn5hRWITx1NKDbq7ktbTtd7LIFIvvgqpJGzR4cnqn1RLzRMHocQrsNX0PSbE6zBo7BMAKCQagNwh3lWNjtER947CUIdjxltThRpJHeG8CD3ZV3NXQmgkiq2uhpMMVcvht5bnPEh7Amnv3INim41LNUxaz6z6xtq8XEQ5JNmFi9KSK24IwPsvM+IcdWfPIml0Tr/jvuUOpw1cikp4QI7DokvcycY1aY85oPdL5jlH5PvV689wIZtRC6E6KFRU+T56YSr3p5vhCxuCmNQSh5mVuuzJWykT0xAVhKt3nQhV1E/M5Jj0tJRbHyrMSbnu96QTHMkSpsfw1sUznWwqk/Jy7p8gSsATlxzgW1nVSLlhkuIOq4yy5xEkLksr4TH6JjF47Yd0K2ZGV30MO0Qx/sbhaMbYoziyaHrKsRD8ecfaJDiXd9DR1hkDqYKPPgf31VsjB1UWj2HEBPc6Jg9ZY6Kx9NM8qNLClzrkLkAk+uDuMn/BKt9FDDM7Yb4VypjOexTv4NLG2ePtw/tLS269j5WyN04Vuaq5AMIJT7Wsog0lTDid3v58BHB2P/8zYXtEx4z/5NHli/GvxoEcVykIg9/WAUpLTexV5gHwk7dHdBDlfTe8cotj2H42SYCHdq60izps+PSzSmJOr9qE/oiUTZZo1HyQlGUKxV3mEsxegK0AC+7ETwg+W7UdAjG6+0IbVI988N61D++ed3G/XkpG5nRUw2oKcFTgQVPa2nnqn0eP0DsxNR6ZVMIuqSXE1ZRu2JmOCZhnkb/PEzDBcdoKjE1tOy31ec2vi2CNZHl+D1jXjM0jd+pkr7ONRfNJhX+ofUEJzHtMMImBcI6UYR64zKqJHjlbN1PrRL6gle6f0Ok2PFl+Endf4oXap1s54TCDHHEPVFSAXR0Af8hNrQ/QWx2qHCUk1mIti57hPcWSc2E5MaTauCrrzkIg1aPYTvwX2XkhwyxZ3O+QKdnYm/H1NtmhZD/agS+GMYnNgafjsoVemfKHM980OkvIDTSVNbOwWxUCJhztxKloWZ5syhgYkKqTGI+jwgPOH0NUOXefTIfU241pmXzcBqFDsPMWIfqh63knAvFb+fxltP2JURqNFMFBk9L7eq5R2L5gMiZEA4g2vKA6JpqlRc3FwBQjRq4T9l4HiRO8aMaEjSzuxL9zwGvRDQBBvwpEENfvXEjI+iopiTheCxK8KxaPAD52kyXepqg==","layer_level":2},{"id":"82e5534e-5b78-4582-ba77-8590166e6cd0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"关系型数据库配置","description":"relational-db-configuration","prompt":"创建关系型数据库连接器配置文档,详细说明MySQL、PostgreSQL、Oracle、SQL Server等关系型数据库的配置方法。包括JDBC连接字符串格式、连接参数(如host、port、database、username、password)、SSL配置、连接池参数(最大连接数、最小连接数、连接超时等)。解释如何配置读写分离、故障转移等高级特性。提供性能调优建议,如连接复用、批量操作、查询超时设置等。说明如何测试连接器的连通性和性能。","parent_id":"3268b632-dada-4561-a9f6-4ae317e64f29","progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java,datavines-connector/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java,datavines-connector/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java,datavines-connector/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java,datavines-connector/datavines-connector-sqlserver/src/main/java/io/datavines/connector/plugin/SqlServerConnector.java","gmt_create":"2025-12-25T23:44:33+08:00","gmt_modified":"2025-12-26T00:45:42+08:00","raw_data":"WikiEncrypted:cNVFSWS+PYTEUvkCsFWSBNgz8dW5AXCRlfM1GNMfEWcSeRD7fPAzBnHF8wAl88nH55fDbKb0LrygkeeY+EkeoJB17rcZM/fwo8+H/4GPnq5Y6lzzGfFlRvlQNRxWcyBjc+rPmFUaZOyVXzNP/0eZEPdYh/LLrCa/Mj/JcNm0W8wyryucXIPOkBxpYMcb0/0gB5DgHvWVYw5yZQJ6vJtFBFUqItGUqTx+Lvlsp1k813yqjtVhvwtZMz7Vt1YjV8NBbKfpdVp+5ADUw+cvy21b5ZJzZaVkoIW9f9xlwjgAFas+6vsnr97YrzO7T8ZX08OqwM6WRNYLV8Su/KRbtg2PUBxzCcK1mFnLMSYKyamLsS7vdiR+h7ND2sGpZOLfANfGBPlkKooNueldge4cDspbbaopbN4xZBS7Z9HZwLOIUE0v90SLdRzam1kxu36WhL4bi5vTP1zh/P0dZYXkO2J1a7E3/i78Wi6t0d3Y8CsW0mV+vFmDsE6t2sjNc+swDcovMRKWkaMrmpdzmm3Lllyxv/CNLl/u1Mnhzr4ApazHGr+3GemPTl68BTzfcj5WuPqqxrHDKCIt35kHQ1ZAaHiZKXhKBar4T9yssG66EG/TMGMLoS/T8TPZiinZkuU7oep2rFiw+UyVIN0jWObh6ZvgDlOFSegj+l7n68QjxDyQQctejjWowdppjKiV0EDd9EIJn9zrUIOeLcccUVURogSyTZgpwr7pQ0EfSI5D/nSmM0DeeuZNFriRRrRbmc2qfBdq0uY6ggyxd1lynPIaVSxfmfmDm0UoA/vW+lvOvzEjmnbFO9GgW/L6eVwXSNla9oZUuAUdY3XVlMZx86UyK5H4JYrHr0Pj/8axawdAr+eqKmXM3/A0TCD1Zie39rz/KytyeI71rmv3dtA8RGhb6lQLbD8JAPA9sxfBeJ/vDvzqxnykE2yOn4Cn107C+v8jjWVidbPHWU85nWPtbwLC8cr4PpAfNtVnHIgT/Kc7fasJbuMWfTzdIQUwxZwUGRfHYiXRPXwAqT14xw1oqLIWYZysftnRcnKaHGHHVUXk6SR5patkuauryP6iK+T5//RXugLusIYyV2uukduTXrm2ZhmOuYT2nC9fUiOirRQ8CngQLSGG/9vNTSDsHQHwixQGPUdjPLR6/emF32TXl/cPQ9NcymwYKnRx1D0e2MI36pQpAIujR1hQSbpWTY0pcW+9+Uq/krGYFKjxybu3ijtTP0xrBJm+rNuVgCuUxqpOcOzW+RVUXLYcmrHQU5KKg4TJg0lbxdzfmngoRhO51Y1PJ3bxm3l/dFXuboc3YiGqHgmdChG6mreoVmZy6vyo7NPGYwL2jjXmAFv57ctJnRY9/rlTzznPQBZ93E2v/VVvr11hho//cdqSk9yX8ZqJww8f1ibyTbxlcOzwPRJXKehDcFcyZW1cnnVaTU9o3a67132HaQbTcFC9sosql9Zp6CQRxQubiCGo0SPYY3L7Ub9OBSrG2GD8WobbytWHIIBAUTU/ksbbekURjxjtPreV1fcK1XcUIGbZRhAE++r4wPlQ2bTIjtKRukcNvFMoMRJc0F7DqaFLi/bHRvb7LmR27NIx3YCEfg3j9tdQCrVY/M0hAVqHT1CHH2u6X58fLx+5SMBKhq9K8dBhrpIADb3tcYpktsbw1leIzjw5U2blDMZ0QwN4VucZVhoAJw2ni/AkwNwND+kq2rpRumwD5oLjwr6GDN7QUsTxrS8TJAAKULn9sTFiUGfgQR+4sfbBBxf2Ay5bZifaw6bFU3BHGy+9iO9cr8WVKDu8Tkepygae5JU47MUiBpl762AhjPghJykrpzOfNwM=","layer_level":2},{"id":"9a060c11-69a3-4a51-9fc7-0561602d8775","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"认证配置","description":"authentication-configuration","prompt":"创建认证配置文档,详细说明DataVines的用户认证机制。包括JWT Token的生成、验证和刷新流程,验证码的配置与使用,登录会话管理,以及Token过期策略。解释Kaptcha验证码的配置参数和自定义选项,TokenManager的实现原理和配置方法。提供实际代码示例展示认证流程,说明如何配置Token有效期、刷新机制和安全策略。包含常见认证问题的排查方法和性能优化建议。","parent_id":"67c4da86-576b-4264-b187-42216255a143","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java,datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java,datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:44:42+08:00","gmt_modified":"2025-12-26T00:46:58+08:00","raw_data":"WikiEncrypted:uxAckj1IXK2TQH//kEdeBEJyRR/tNQuuVMLUPk8N6guvt7hpRNiz+nAb5md+ynMkhbjGOHafD4mXdqK4uL1MvRAp0OEUC4qCeAFqaJreikORN7W0qU0DdF4otI8XxkTsjSJuy/nY53i2zNpVXwdJJ1A/i+BTD4ZMbjVZE7I0YjXtrW2YYn5Snd6HWshHvkbM0Zx6ZewyLgYN7nmW+HaihEuFqvM+pE6AluODfhyEKJ0WaCON0ZLqmGGphWgbPkRAf4NnNBpjj/BI4iCHIqIP5H8VMFiq2SrdlhRsZk8VApIU+WFWsqq423oTqDBmlL20AlqYyxJGEU+Z9mmzkSUrwDce85PQ+FG64X1dmLMwIUUR0VOqtXvrsUKuZQa+LaOtmF7tTngiWk1RlATKhEP4f1U0TPWi30IMtdGFI7LxzXG4CJwNWQDAsQr8sOF+hkSFuVtLxQ3Po0XDjh/Rrm9cELlxyBeUzTVvCLxPXCSnZqroKlLT6JgCvtiLnSBReiUyw8nzyPvL1KDPS1xxTXjj8RkLQDrfHXnyC9uoWtuD7dHPcfcdWugiqZh9+wPXXkDO8uCgxpSj+iNs2dWW+ySdnEKXTUgnmxxWKJKbwLU6qCEgqC4rxNgB40hsB06DxnuqeCaCyBdEQOH85ZHXuor1gdYELuW0dlARebKR03v7hmXUwP4eAPA9jcUB9vu5ZrH/sLRod7yGj5uj/neWk66SMQ/E5V4p6TWkoJJyF8vgXPQfy8lwitN9AHYjT0KfostYtEz3nbnqa+KmW6vKdjjDtCbmedVJ4+xFw0jBzKEL7Pb1IQb6RjO3zfEQu+jG//lFClZcxkcnGi8/uRAGz0meJKY+XfPM2XeUfeP6+Mzg1eBXNn9RxnGeT8s6FH7kwAXUQdrL47wUZMsBqRvyA8lJ+RDiBi2lQGjDOdDG1sDwfMiYVtq0mQfZ7Ize4hXaYpbDnPUSWuD0vaCDEuXjhB3HbS5nvMBpoW8GzoFpO0lTdv3pIApVg3DF3EP3qPsFCR2wUVj1AiBQsn/dHgRuUI/tRCB7g16fSh8c48NzQTXywlQaK/PW8c/88nQEWoYMdQazfRH5QxAn/vWHXzkM28k8dC6TAS/nscnlAahbVpCeQ00QYZ4+AwntWTCs4GaZAqrVxTdyAiuTz21yDTxwLxk0brKl0sFZl3hbohA4B56yGa81Xz6Arr5bBTj/La70vkmvVMn5TqvxlOTQ5MazHfovgJKCGGHLUbakw1kHXU3oKG6ua6pYBJDVK8dJrVqUYlDzP2QiKMZpcE6V9LUQM4nBRd1eId1NpVgHqTH6qXjFvb7Vk+VeuSysfKjxxEpVroIR","layer_level":2},{"id":"a4229e60-a19f-49bc-a5f2-fef9a3cc6e34","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"图表类型","description":"chart-types","prompt":"详细描述数据画像中使用的各种图表类型,包括趋势图、分布图、热力图和柱状图。说明每种图表适用的数据特征分析场景,如趋势图用于展示数据行数随时间的变化,分布图用于显示数值型数据的分布情况。解释图表的数据映射逻辑,如何将原始数据转换为可视化元素。提供每种图表的配置参数说明和最佳实践建议。包含实际代码示例,展示前端组件如何接收后端数据并渲染图表。","parent_id":"d9c6c09f-4495-4230-aff6-8582fcde95a6","progress_status":"completed","dependent_files":"datavines-ui/src/view/Main/HomeDetail/Dashboard/index.tsx,datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityProfileServiceImpl.java","gmt_create":"2025-12-25T23:44:45+08:00","gmt_modified":"2025-12-26T01:31:38+08:00","raw_data":"WikiEncrypted:yV844D5O8AJCQC5NtY1ih/X34OAcBKhNXsa9A3e2RUzxmN832mjcqsdRfU+xvBMOCv6o/EAFft/0mT1XYMnkKbeJdGZTTVqYh/0c1aeyyoggGFW/v0L8vdDgtQMld7/qINZTv/msDRyo+hFp0GS/idX26YZSgwtGfRu3yZZ48N8SH+41oSw+SGxz6zIsug0AG19+/l8O+PyWQZ6hjOTzAB37/fHL1FJjcG3A7AC86h7/Qk4M+B6OWLpRL+N9QX0BpsBcT+AT0FAgh1Ut3EQfmb35IVFomKoJbWIYXZzhdP4LppgZ4PwCL1tPXgYpNYpjCeWUodpLLbgChv0xoLwh6uEadOw80t/XBn5GSWk5T69khy1IQrbDwKfEV65sa+t5YO2Q7tzVTr6MciApwUMuIjwEGc9ZtkHQoDqRyCY+RgV4Q14FL+3arWWSMsF0DVPE/i2m4/P2HT2kbqOL3oiVAYs0fyrU3DZ/nvunQRiFPoorFAM+FuTPkp9dWysC7bmJCL+xQqicPIR4nc2thiU84C5nQqEI9Y53/z+1ZJ3myU2P8vyntO1QEyaSDni72BwvkpIKYvVfEr198B8iidxpFoCwu8WMIqrzzrE96N6ezPRoikNlWfl7w0ybTdT+gu4pyLc+cXcY/aCPyikpPLBP5B/+8RlpdEPgEWmOJH8qp8FACb5AN699RbZH1Ok+5lGbOYlKAPx7Tek5AVj2yzv95WG5oRoTytfJROCmNzE/uBRmExacZ097F5Yz6lfVGx363u6KkQ3L6Qv2DCtiqmpc1Q0CvBtOYlGFTVftXm8FJ5F/C6YQKtPkQAXEILIuuACOtx5QLpBMbsnY7jwGKKTuAXW2gCUqsaJYJZxY7pAX870RKEJRYZH/jU0ucVbiAEToeJpgsy12Lwmoz7XUqOkgSBiPznqh/lN/QONFcR/Y6/4rOdlb6hXykLuEZaGmnIo8KsZ5Wm0bXNtzLN1Fd1cuOnKhCQf34GknpRPWNI8yK1kUybKOnh7iFYfV+GJ9ZgDv3N6OAXE3ES8ki+2tCS4fT7EpdoAh0v5im177aB5yrGJj3MxlykOlxIiEsWI+psspQkOLMptinywbdZDvKsGkrUBMq9JkXWUQKMfh52W8WqBYIrbGQYqVu02iHcenXnjdg1IZYd/c79WD3azMcxI2l/Rwi95xLl77qMllPDCFHUs=","layer_level":3},{"id":"6a79461b-e8a0-4873-a4f8-eb99eedcc7ed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"配置方式","description":"data-profiling-configuration-methods","prompt":"开发数据画像采集配置方式文档,详细说明通过Web界面和API两种方式配置画像任务的具体步骤。对于Web界面配置,描述在UI中如何选择数据源、目标表、采集频率等参数的完整流程,包括界面元素说明和操作指引。对于API配置,提供RESTful接口的详细说明,包括HTTP方法、URL路径、请求头、请求体结构和响应格式。提供curl命令示例和Postman配置示例。解释两种配置方式的适用场景和优缺点,以及如何选择合适的配置方式。涵盖配置过程中的权限验证和访问控制机制。","parent_id":"d3911c90-857b-4391-880e-b23a3893ee7a","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java,datavines-ui/src/view/Main/HomeDetail/Jobs/index.tsx,datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java","gmt_create":"2025-12-25T23:44:48+08:00","gmt_modified":"2025-12-26T01:31:51+08:00","raw_data":"WikiEncrypted:YZI97ep9QXDPfRNDXs4+JGwAht1j93lelyy1l/cm5MtAEj6UYN1rRDNNVutEwk4qcX+hiUiC3hOnxTHIBC/iT+OAVcX3WcUe6nkM23kiYGOpwwMV9JDjSmzv4E/EqhYfbKNLEG/Y/OJ/bgcL0boK7CZ3Hhgo9Owm5HjgJGMd/KeE/fuQ+nrFcnzWkbh9LHzQo5vttva7+lkC+8blJzxEoKabWnQI/1rFyE1KqaRgG7Pd9/GZV+7qMQ7U9knUPR8ckwtZpaqpQz7hj1KNfyT/+V4Y+dWwaUF4P28JeGV6ZmE2JMqXDkVj/0TXPVOhIpSMPrSi0kdrI43TctAypEPD46/eb8i1TgcSCEckyhHMag8QFM6GeyPs+O+w5eIveMC1ARcOPtFiQcNSMogICcLkYyACC73nLGFm8OsnsNEHgf0Jk/+5mqMguz6aL3AnVVb32iT8fIZ3e3iPUAlqFUA/m6VZQi3BmXHOo6MLG7gyIUKJUEKBXBhG4Ddk1Hfrj7oq9sTK6WfFP3Kchfmy5QKMa1FVyagNvQ6bE1lcmHbFyztrIaLxuybrptz/pNv8wKDVdybtb6VYBPn2/Ll9OTEo843Kl9zwfZr0UlV8d8LxDFqxZ5LHSknWWe90n8T/3UyJbpbcZi2ylY+nreuBSs5+S0OHBogd6aNfFsDKWCSFZSkPiy3zW5/CgvZGKgASETTQE0mQyi6zwwP/aOWMvjhjpSuJW2Eojm90ZoOb1wuqkkMLCq27ZugGYntZrtrbumi7Yn1u63S3N8tK36ptrMfz3Wz2lKgtVgFE2zJQ6OqPf0n0P5LipBppTU9iKdFcEE7YMfv9w3MLOw5YNMUu8iPLBSbiDYSmjPB5Gs39tIVXByI0F8gUo4TnXxjfv4BMfyhiu1UOtc63B8qRVnfO/zGxfv1/ndCgxBcwIrckE1TSl+klj4X3o1VgHYflall+9ssgwqAdQiLmqAGEJtg/irktmgTvpMduc/WKEEEev84HUuQbY3UyQWuwfqaYIwlEsYVdjOhtYAZZswLJX9be6+NPPWyPl/xrS/7erNdS8fkF2NSqczhGtugLV7tRBAeKI8AOpbS+Pc86OhdJm1ddAleQV17eRDxEe9N7cW+KFMWD0iRpHXNT3wwplg195KoeQC3HER1hqpi1r45AuBgGQkhkSMvParplRt+1vW64fedPs0GqBu8304jceZmwheQP1fre8M+pGRfjbNPeHI2qPOUu43EvSou+MtgIzxdaP+cIjJez4+W9DAVdwyRyYQ4u9xMXFtY2UKnp5mJ7lrwdGMrcThGRwA5wc0niD4UA6hRvwaA544eosuzQAUm6fPQ0ocKOUwUP+lrfij/ng+3nQDI2NXJ3Y3LzHnAcwnKikSV6NqXzlStmFVEe7zT3x7wimADlX6U1UAveYY2mN8h/aAqkCfWcHLVg3wF39BbjWjZZtCWdhQMyP4vRfkh90er74UWWmq5oKSVjv6bC4wSEH8sEcLzkMgqLSLAzRPs6JZrzHew=","layer_level":3},{"id":"bb7eb5cf-d368-4e47-ba97-fcc83e5f3de3","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Server组件","description":"server-component","prompt":"深入分析DataVines Server组件的架构设计与核心职责。详细阐述其作为API网关、任务调度中心和状态管理器的功能实现。重点解析基于Spring Boot的MVC架构,包括RESTful API设计、JWT身份验证机制(TokenManager)和全局异常处理。详细说明Quartz调度器的集成方式,如何通过JobScheduleController和QuartzExecutors实现定时任务的创建、触发和管理。结合DataVinesServer.java的启动流程,解释各服务模块的初始化过程。提供API调用示例和调度配置说明,讨论高并发场景下的性能优化策略。","parent_id":"5a95842d-bb17-4f7e-b3f1-fa2cbb84163e","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/DataVinesServer.java,datavines-server/src/main/resources/application.yaml,datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java","gmt_create":"2025-12-25T23:44:58+08:00","gmt_modified":"2025-12-26T01:32:15+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjLgFh5SHFG7ICUc4UIH6A3VjaLWbJm6QkaI1m1O14dkpni0sCODAB+Sly7CsNp4AmX1e2iNLXFRG0K53PenWWlZJi7ILsDf6pubp2dmncmFjbDWp5uHB8mir+lDcgqbbwdksUyw82Msp8ZF/Q5SZBIU70qpSkA5HJgQfCFbz0zsGFHLO96tP7Qj/AirywQLfwKiJVLrF8/jXItP/e1svfFXa8sdTaY779e9SyzD/WdyzHyRw9xOO97MdSy/RUTsuOPb11eyqMyWgiRVKyj1hnaa78qXI8m7k5Wi2dkdidFCjttXgaHwWGvGhfgYbBJVG9LpknsyWRL6SUqHfmnhleoqzMF5TWqiURlW67JIqRoj7+oUpPiKKkH8JCP9PXalsnsp99L5HYfKfdrL96Ssbd9CQRJ8k66mxDS0/MHQ8LBHRqLHkx1wZZ8sjVWRpGE2yaRnYNNDFSlofZZfdh2/JThSioNL0ZDplOyEZgySPtFGqlZ0UkZe2w6EcbKrvgnGuW5c9tIRtK/w+QmVyPcXw2Ge0f4Nj22V0BzX1vxR2USv0GQex1BluBWonZJJpjt9bLQmyhftWHsvgm8tMIX8XoIX+V+7gRFh9CMNXNLKvmAAOZ2Nl5T8ddeTsstVBjAlgo4QRGcWizQcgKGhYgL2eAmaPbiD6Mw0bRLDoFDRoC0PubOeGYvN9XjBOQzLrvFFU42usxIokE/BFeRWxY0MBpV3/3q64SLSTrEc8vJd4t5WvxCZPgWCLMwP2v9lH7Lp5FyGUNWIAcdlUOu2HBEDAD1s+U3reSACSoZ4cTEir1tYRFCSg9dLcjgIlbtiiIbsN2qlY4HcgaiUSptlTt8lvbCE2tIFPrfjKQRa7ABx0qvcLtukfUOWepxenGo3qkdvLRX9DE9GUYweQ1TZcBMXweKMUkQe+0Veht2/JcUa5fUCPZiE60xSA+gmEIdd4DS9gz+RpsNOOO625iknpwgMC15vAsOJ+K1ZAD+EkJx1XNqpiwWSkbiQM51Zo3GaKXBJIrqoE2D4z6arqxOu7yWhp9pLDqT8R7ASWYLb3c6cV4naLJEO4p771QdIb8Fc585bqp7JzjPxyQm+bB2Xe+TRnU6meyL1Byxsgul6iXbQvfycv4q0jn03UU5gPBDDyOAQqlwFrBs5yFG67TFEXPLDIGwJesGB9R0cvdqEbYuFkJ1/hId7eBVDAgX/gnhDD3o/A2bwR68D8wOtY+64qI4Sukhfo476A+HaGG1/Dtm/vnu8eYN6qIrzCo/ApMqp+RjqZMqwG0jyJsAwBqoI2wloFRAp6En9VWTJWwbs381zWxsprwFQq9jiwn0tjcb0crGQUA3/p5m5N3XK+GZsSq01kChiCuCRAZAGJhX64Y1slP8bDGCN1rF9ZLA9st9lsn3up1ETY5lK5pV/1lFoxTbHQVWWLoP8Y24OZmBb83kJ1PVMpqXjbZb/fi+wbV3AA+EB3L6JeT7NxAznjv21I8+k+Q2/hOjFg6EAmWqM26D99wzaILh2ZQ/JRSrXNUUcC+ZX5SbS30mWI3dsFTCaDuRQfF7ykm+6g9Q/MM0HA9Zt9wCXujGpkUODHWZcWMXeoZjkNUfHB3rPqbzWAVUblsfA3yBWjaZ4Vfaw+nMbyKrMtg3SB","layer_level":3},{"id":"bfcfc439-ddb2-439a-b44b-cc168804d1c9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务调度机制","description":"task-scheduling","prompt":"详细解析DataVines的任务调度流程。从Quartz定时任务触发开始,描述DataQualityScheduleJob如何创建Command命令,JobExecutionParameterBuilderFactory如何根据任务类型构建具体参数对象,以及Server如何通过HTTP客户端将执行请求发送给Engine模块。重点分析任务参数的序列化与反序列化过程,包括BaseJobParameter的继承体系和JSON格式的数据封装。通过代码示例展示单表质量检查和跨表准确性检查的任务参数差异,并说明调度过程中优先级、超时策略等控制参数的传递机制。","parent_id":"42102899-382d-4ae9-98ea-ab19ba59b352","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractEngineExecutor.java","gmt_create":"2025-12-25T23:45:00+08:00","gmt_modified":"2025-12-26T01:33:38+08:00","raw_data":"WikiEncrypted:sdobwW3Qsckh0ghPExsMqkgInHQmajp2nUSs4Ao4ywMo4vSHgmfb0d/aVM2uGayJaOsPOOD3bDL4wZaECA0BWX2eWJejSRTqaBcitN+DtFNx23BVsgblBj7sqQ36a6dldMMbgwNV0vpIIoWJ7p9mpaxrV3ws+/Lttb/kFh7PgXeZdb67DPdDlFFOptGljw5hoPNC1s+EggUcwowiH7qWkcTNzj4cq0T7aM6z/yVHiQP8j2xG947chQ/gy1hAc9pKaATinL+ZLIiBNv6w95c8XtbaowY1D8plH/5XjaSfJxNza+cccF7PFYbg9pa3nN8cf9TVcvNF+yc0O52ANdVgezebC/jpq8tdHIIHTOyrwqYu6Fq9TMfVIRrlt3rgq5zBP8GsC/TsHg/EmL8D02DFEg5P3BhEBnAAkuYj1bglGIdZjWjYKbV2qWp0fSF2D5JUs9N5lFO/sdmqfZTBNh8MCKdwyGmOCwJuU1wlXwlbFhrkXgTe8igzjCQ8Zt4VkIkfqhhov0qFo++nHPyQw8qiG+asCvGeCbqFzLMFiwd8T5zomqmIUoe5Cie+xBDfs0L8kKj8WX2YlzIEpi6zY7/79tjzHHlzDply4oPi0S3fiOM7C/aPJuuQp5lDB40pYxD+o/e/qd/vIZyA5IWYDsDLlFnPVh0wVRYW+8GSbe+sZcn6cg/rk8+1GI+UC/af6/EIOkbtIMwFXmKLk8l1pmfI7DPcUgqUFi6yfqRSn+tyJWVhpyrRKxMfIFAiaL21MfoIHWnaBQaWqHsnpPKmg2g7qrvdeLHbhny7NjCVbp0dFnZmUdoRcptBpFDqVpoY4w2MDUKcki7/6VahPm4G5p4rQv9pU3fwl2CoxYCnd59two3L0JZf9ARYBNgAPavzO41B+tPd0JyMkR38sjKkFQt6CM8TMV7rdNhrYJyRYuUp/YsfrgJxblTtgPfg7q+sltd8v3QUB1l0TOBIUME+ca0P7E6J/Tn47OeLpclyzALx+/BxYKL7pVMDg+BKGaU7Sl8k8HrCl5kU9bscBisgbDAYXmjeMZscFblIJJzyFObI0Enko22w303V3FSYtkZ/Lh3jAVf569RBL12/EjlzSvNytPagQfji1n8sg/cW6IDhruVYnxqEzWxe4m88ay/FteeH+dKNSVXGOwhNQar0tog7JMewrOyXywn1R9zKwz7+BdQGUBVW/8MQBNYImVBSMA2MdUs5yuHzM1i0fryt/sZPHBFdHKhssugtcp3pVQhiFtZyzBePax3BjYCpNxs6UXgO7T5xIxXUwuNF9tX2zR1pplQTtx98Y6xr8gWbPGmfWpiMAhppW9tRJf2hkLGOAimCWtndo2M8EPp+kGDzd73t4EG2rTKxiHzoy2qItM2m3/y7KoT74CluQd913Xl5yT94FZWI8xxvKMRJNkXJghyBaVKpqHcQJuV0JVvEWbPzqZFLWoGIQ/DXUfjsVwJcglNIv08p01zUje/f7daaGHlaPJAwIvVL9SSqVDxPX4CnCS/+/rR5TJDOnCsUN1i/Pm4MijZB36tGAjkYnyrBf0sTGEY7dqex5oMZHVv0I/PvAb/pPvlLqwPE+RCXxwZu8hyz","layer_level":3},{"id":"389c117e-1ada-4683-80ae-fb508cb84925","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Spring上下文初始化","description":"spring-context-initialization","prompt":"详细解析DataVines的Spring Application Context初始化过程。从DataVinesServer主类的main方法开始,分析Spring Boot自动配置机制如何加载application.yaml中的配置项。重点描述MyBatis Plus配置、Web MVC配置和Swagger配置的注入过程,以及Bean的依赖注入顺序。说明AOP切面(如RefreshTokenAop)的注册时机和代理创建过程。通过源码分析配置类之间的依赖关系,解释类型转换器、消息转换器和异常处理器的初始化流程。提供Spring容器启动时的Bean加载时序图,帮助开发者理解核心组件的初始化顺序。","parent_id":"4fe521c8-eabe-4899-aa88-38fcb7db2d6f","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/DataVinesServer.java,datavines-server/src/main/resources/application.yaml,datavines-server/src/main/java/io/datavines/server/config/MybatisPlusConfig.java,datavines-core/src/main/java/io/datavines/core/utils/BeanConvertUtils.java","gmt_create":"2025-12-25T23:45:04+08:00","gmt_modified":"2025-12-26T01:33:22+08:00","raw_data":"WikiEncrypted:oMjp92Jc/ftHbGobNjX6U658HNfhKOkfyT4UN1Lfc3vIU1YJZAkbUuPCDdMg0yFoNgzb1HDW8AG8CnZR8vJOXh+kgz0kOj9H+oT7h/5VTZTKRrb4e6x94JdHBwHOfQ0nc1MP7SvT9we1TWh2c5T886V+uRCnOyo+0eOFmTKGfXU57G0gypYiAFl1X+HrarD1GHZNJz8OEKJhQJy5JPmGCSj3+yM9QE7nYJlXuYPAqand9QjGZZxyrggTjBqvA0cU6tqgxefVOnekM9OwpovBUBjhUxH/OJM41yGa3uT6o+r/c9nBak6JJm1fawFCqYVgDvQzUnkHWovTPtVIgLzwxRAZOwTvfFvmySt8M+b6jIRFZgJi3Ra9i5p4GLSNbQhj44dxlh7H4qFZQoEqvXMSO3ln9pbQYko9K1bIGz9HWQkYkPfhV4t389Qrlc6siqeGZ2CHmWzu6djQiT/ggEA1tjygT9TvEFA1P4tUh4iBL5QHFR0QPsm+zXgx1jooZ5LfA2EgDFlVcGaxW8RtF3pVCdIdbM8XSHx0qbHADnuSAjLYjqcy2WjlZIVk6j/XjvYlsgemrr58/0agtXozBj0IfWleJ7b+AKEEPeE1jxzdJdrlk2RHMuXPYg4agvx8LjEmoeJKE+MGuSf89gJ/prIR93eb/CHQWGeQzap/KclaCqm1fquMqvLOR2oLgvqU3i+mMORqnuPAaqz8NQZAWsKMYVge5KAHz9Fsslwc6FMEc1Wyd4nJjAjY5mac9ekF73MnHSeSFjNyq1fK8zAeAUHCgtUiYNrkCPd+k+zvt2EtK5g2AxyV6hhrkIwg79M8fwA6yratY9bEykijO5U2aHGqf4jxuDx+VZBuCBLjaFdKpQlW7gX2v1FRnYqWENCteS1pYIhWwPKh6bSFVy5y/8VuG27MXOYWLn2JuJ15lATy6GsJLPTyU8FLFrkT4jiH5dvJfyFa+U09LzSEDHFpQFI0maE6d6JquSdXa0jilkIfYFdBwRnL6ECjXuMeBJQX5vASclf3UWDiq16wZAlck/YxL1+DdG0WamZCNC51xxpYTcirqW2ERnJQd8wXzbnqcmSk4u20xr1/gxP7B5CZO57vzuSeSlm0UElj1QKLGxKcwpMpceaAoFspndJREd+x+dfyRA1jYRLOwuZ8eZAroIOrCN4D7SUrNo1ZZoYuWWMbTPa03Kqvuoao9NbsAG80nfurlZvRTglWvZeggp5XDRImrw1Ef7Po0E5F2T2dGVasgQAVPp0Baxx63wAOFnRvKrFhSk944bsBg1Jixlfj0qOd+p0DEG1xyXVUM5auxGIV7OP/p0dJGSZ1Hp0esGt5oVGf4GAI+a7H+O3zreiAGECdnS7V29hLnS0EtXfbA817wi1g3eHatYYj7njC0qhvcErqhg9iS4E6Vy6dXaC1e/qRd73iP+KeZeIDiWZdzPO8led0k8IY58mWSJ8/RhZzZ9/EGG48IQub8nvvxgiaZ9SP2A==","layer_level":3},{"id":"0119e5f6-79b0-4d58-813a-14a0a719454e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"单表检查","description":"single-table-checks","prompt":"开发单表检查规则文档,详细描述DataVines支持的单表列级质量检查规则。重点说明非空检查(ColumnNotNull)、唯一性检查(ColumnUnique)、值范围检查(ColumnValueBetween)、枚举值检查(ColumnInEnums)、正则匹配检查(ColumnMatchRegex)、长度检查(ColumnLength)、平均长度检查(ColumnAvgLength)、标准差检查(ColumnStdDev)和方差检查(ColumnVariance)等规则的实现原理。为每种规则提供具体的配置参数说明、使用场景示例和性能优化建议。解释这些规则如何通过SqlMetric接口实现,并与执行引擎集成。提供实际业务场景中的应用案例,如用户表手机号非空验证、订单表订单号唯一性校验、产品表价格范围校验等。","parent_id":"9b5eff2c-3130-4124-8dac-52560ca652a4","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnUnique.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnInEnums.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnMatchRegex.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnLength.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnAvgLength.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnStdDev.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnVariance.java","gmt_create":"2025-12-25T23:45:13+08:00","gmt_modified":"2025-12-26T01:34:27+08:00","raw_data":"WikiEncrypted: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","layer_level":3},{"id":"54f9b430-fe21-493c-8d14-bafe2c3002be","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行平台","description":"execution-platforms","prompt":"开发执行平台文档,详细说明DataVines支持的三种执行平台:Spark、Flink和Local。介绍每种平台的技术架构、适用场景和性能特点。详细描述Spark平台的分布式计算能力,适用于大规模数据处理场景;Flink平台的流批一体特性,适用于实时数据质量检查;Local平台的轻量级特性,适用于开发测试和小规模数据验证。说明各平台的初始化过程、运行时环境配置和资源管理机制。提供平台间的技术对比,包括吞吐量、延迟、资源利用率等指标。解释如何根据业务需求选择合适的执行平台,以及平台切换的注意事项和配置变更。","parent_id":"9f664f1b-9947-4d3e-a6b9-ef1a47485c24","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/enums/JobExecutePlatformType.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java,datavines-engine/datavines-engine-plugins/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java,datavines-engine/datavines-engine-plugins/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java,datavines-engine/datavines-engine-plugins/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java","gmt_create":"2025-12-25T23:45:14+08:00","gmt_modified":"2025-12-26T01:34:45+08:00","raw_data":"WikiEncrypted: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","layer_level":3},{"id":"007c1da6-4f63-4934-96f3-2a1b1b854abf","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"验证流程","description":"validation-process","prompt":"开发数据质量验证流程文档,详细描述从任务执行到结果评估的完整验证流程。解释JobResultValidator如何接收执行结果、提取实际值、获取预期值并进行比较评估。说明验证过程中各组件的协作关系,包括任务调度器、执行引擎和结果存储。描述验证流程的状态管理机制,如何处理成功、失败和异常情况。详细说明验证结果的存储结构和数据访问模式。提供验证流程的时序图和状态转换图。解释验证流程的可扩展性设计,支持自定义验证逻辑的接入方式。涵盖验证流程的性能监控指标和优化策略。","parent_id":"89150110-41ce-4344-a684-350172827c8c","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java,datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java,datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java","gmt_create":"2025-12-25T23:45:22+08:00","gmt_modified":"2025-12-26T01:35:16+08:00","raw_data":"WikiEncrypted:HZAyTPtg+ulTaOiA6Qoi0LHLfFvg7ulnGvFlOiqhEB7v+Wkb6YOv1SHptnwShancVfuq0BwithpFnlmQ3PKfvkHsMquY+oKp3AjJyw3czqx+ks5XqQfZsIu8dSli2zvV0m1X9EWmOYoRZu4Z6cYbkBTeR3G1+Iwyvn2vY7DBo8kSK633c2Xqwbu3tjrDByhGJLQy3u1wHCpNyRLT7mCPlN9AN+4TFJ174a/NQ68R/OTASSk3V0fZs2bchfjUjq0XS7gRlyRLGX3/VKSeAvUF/s51bNI998Lzwd3rZTx5PFmAncxe4dFoN7WjYj2LScES9NOIhpojsvZWlv9bZ60BzxjIqxRoRo+Il3rgDjZooM2D+MMv+1d+H/dijNiBIXyjv5Mkjem73l7KajMxav2GN5B0sVpUaL+rtPpAWLX1qa7OXg1Qg2JTufBZXb7jKXznwJsB9rDIad4pyWZ3FdPXIFyYaXD96jscYWSAiF9NgMVcXVR7TPDki2jkIipoRH+7veHLXj1Fl61TW8tss+CorA75uoU1XnWR6DPCctpnGwlHe2njN5rV4GOzB9TKhA0t6DXPFVyDVKlFViQEqo9wuZuocOhHnAzLmu5sEJY5mxRwru3nktLKspbEKQNpx8uyI4Gc60RLNLRAzNDLlJuBdl9pqlYB6B7l5wgsrN5a5uFHv7tW4MQQhgWAaSgmpFsOuZ56z/wP75ZsjUvaGyfruMhqImeXDRPMP5AWq10qCxIqZzpcmG8c/k6lhMmHX4yYZ20adLnHVOxVlqrpc+0fVe6b4t5fgcNcyFxG0NDGth4xoE3RCKvS0VLVgJ9m6fEJPjnpD0NtUVA1j70HuIOSjrXXazE+C9jCMykL8bCcNYsEk0MYqaEo5B7d6KB4iNzCMLdHHY+xhhsPdZhLYTDNWsUId4fpVGHiBfwXjUkowgb27GVegl2h+5uffJPtNVOe7VxJMHauG25KdyXdSFQ8pZZY/18Ejyz9H2x46RlrqrEblKw2rOeLrdahA1QmgOSK9hkrdC7MRvp2iNfeJU80i6mc3y6zKZIkUPVFVEGJdNCKIA8zsFTubnev/8dUMZ6T8Zc9V403LCHWCsgR2+VHySLPu3C4YZfO/b3v02p2892OMhHaGWlhnmcFa0D59ypOP+Q70Q9stiSX/tha2JYXJMaXKU+5QarZ51SVPa27kq6TDj74yIhPteYrKlkyOkhFa+rQeH0oZ9L1q3Q4B8BhWXyKtOylro3AMTmjO/mNJ0X/N1St6UbFAoJydguRAOtnQcX1bXtLGTXrPG010O9OgtV2tVk/kXPT+bMEw00s8ihI7gzQR20MY5wdf/6N6+0n31yFL/ke9YLn2aI+OkymLiXtr/LAqEtfT+QUvP3kCWjsXp8prTquWeq5DAZt1GIZnDnEI/273SMNjaAzsQ8A6ZKNbuKyQ1628uZC3NK5vIPqsI6lLkXYUwpA1/L/zfSDaXcd2ktvslU/l3kM7bGbajYNUGdqbR/LlhuSBywemlSDQx3jkUM0+AhP/iKvcSF5jcNkkSHhsVpL0nVj/BdMtA==","layer_level":3},{"id":"cb86625d-920e-447f-a3e2-27f8369c611e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"调度管理","description":"scheduling-management","prompt":"开发DataVines调度管理文档,详细描述任务调度的元数据管理和生命周期控制。重点解析ScheduleJobInfo类如何封装调度任务的配置信息,包括任务ID、执行时间、重复间隔等属性。说明JobScheduler如何通过Quartz调度框架实现任务的创建、启动、暂停、恢复和删除操作。描述调度任务的状态机模型,包括待调度、运行中、已暂停、已完成等状态的转换逻辑。提供调度任务配置的JSON示例和API调用方式。讨论调度器的线程池配置和并发控制策略。","parent_id":"4abfa320-b04c-41ed-aef6-bfdc2fe13c3a","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java","gmt_create":"2025-12-25T23:45:22+08:00","gmt_modified":"2025-12-26T01:36:53+08:00","raw_data":"WikiEncrypted:Ixm4kI/Z7v0V3JxitGlz9SX8evLoqVyBy0QB6vBvUnAvSc9eoTZvIFSk05S4ufPIor7+J7JGiBkSD29KIlb6iOoKKwH9TMs2u2W5S3svb9Fac9hOpBl4OLH2V6HpJKyHARZ46ttdvdqAD8FwqGk1rZuKjRSR/g0WrDOjicfSPOf51E8w+C2Yyd+SaqHypN3gMlnRTkRkLeB3slHY2TecQ94tL70+6HHjtwtiE+L7lfXMQpBs67vlv+Cs2ZQ+QuL9WQUgvy1Q6GJwaVIyXkcMP6m3A0pdbVBMf0pPg6SFjWcEgD9uCOieG2BCbFC+thNYEocZInUJ50iwig6pr4z80ow8al9Xc0ODJcp8TE4e4e+MBofhrWz01urI+7FkRkve+Rqe8x7ocU+uzHGJkJEX3Hf5i4zufnftpL6FIj8HxCe32+NAyGfQuGT5b18OGILe+RETB4T7X5JmcUf9J4IiBk3o66GemwX/gtsCNGFx4Qq7pu3lO0N56RWzDc0IzZ4LtU2OrozxZgNkRcx959EkoPgY783t4kTHwp7ZqceU7Vp8SBatTX+R8Kxj258s9aCDQ2EyJ8rAT38OUmLWYlhqVAa4U1skI3jbFYwYcOug5PBfHecfuJq6UnQ32G6BF5CVLx+O9qVTa6w35F7E8G4ysoHMI9vl5tyV667dO/afN11blP45D2umuEFlT1FkimGB3wLehtd+mHdT0jzEp8imBgLsnNFr9Qmq6Nep30Pr1qYTIJmF8bvrEj7Xw2uhqbAe4yhjOemJiS4hW+7s9x8It9mmsASybpPdIeO+HOZMAHS5gocn7lGioe2PrQs7iCHg5kSlMxEp4B1thIeXFqablIQahNFx1KVD++oLWKJZucx9zMUotZBjKyMMd7BcaTNLEaWWun4na1bdC3imAKQ1xqxI7cSQunPPMk2ysUCuPazJX3OM0KYc4RPC33zdtG5kFX3roVjkRwO5zgvgME+OnN8SjrcKgKCzZOdyK1q++HWY/jdhu3eWbSMl+vSok2Toomb1bBVl45f+8X2ECnIFW5it1PHZvNVMzZ703n05+3W4UkiyeK74yxsiGjzDvOhosByqhScPhY2mfpIA+qAJ5ekFJRrn+AR5t1xxo+Z1y/WYZZhm2YmIp6PznEC5C8uBhV221DxD5U5YLHREt07SjuQk//7YPDLt9S0aJjddrtDjOUvgTJkogvsS1eUIGgQxrEA7kfzk5RoGPkeGu8FaVzDD6ojfaalf8xKrdzY8ILmZ/UQ1yGbihmX7lc+AmUdXvYtaPEzFwa3AftSQTtym0Erj3oJ/C+Rn/n+NrBA1lLrcJ0P74goTTzu6x03K4KiR","layer_level":3},{"id":"149d22d4-1dbc-436e-a0ba-27e764925bde","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"调度类型","description":"scheduling-types","prompt":"开发详细文档介绍数据质量检查任务的三种调度类型:一次性调度、固定频率调度和Cron表达式调度。详细说明每种调度类型的定义、适用场景和配置参数。对于一次性调度,解释其在临时数据质量验证中的应用;对于固定频率调度,说明其时间间隔配置方式和精度控制;对于Cron表达式调度,提供完整的语法规范、字段含义说明和常见模式示例(如每小时执行、每天凌晨2点执行、每周一上午9点执行等)。通过实际代码示例展示不同类型调度任务的创建过程,并对比各种调度类型的优缺点和性能特征。","parent_id":"a2152a18-ea14-4a41-80d9-cc7645d5b0c9","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/enums/JobScheduleType.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java,datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java","gmt_create":"2025-12-25T23:45:26+08:00","gmt_modified":"2025-12-26T01:36:34+08:00","raw_data":"WikiEncrypted:Ixm4kI/Z7v0V3JxitGlz9VxVg6YaXg63iOHORJ9GKaEQu/CmvFskntFlELdNXd8d7/KvRDjT/u8Vimo4KVnqu/RO1Yb5Ru8IzCqz2PsvhiuG3+oliDuIhu1aKG4i+hb2Rfb9AFOXD70lErWEFPvriwV4lP+ADS8QGT4yp4NeVrVGu10B9D1QQV4iX3AhUXodJWkwn3BkXbQsyVwDO2g5RP+HAD0F8ftITl9a5SJD0vgG6WajsQ/bnnERGNZvVDAAVG4lDeL9MaJ0s0th7MCxGhUQegG+iWpUziM6T65243tPPL2exNIuac+XswHXrbAJeC4kn8LlO7UFhdyEx7Iqub6xQOSMPTEEBmHjUIE5BtjzWaNOt5FELa8jIhbOUJ+WHC5QOIUVp7llOLVQYuvNeJuOne6lc5TvsAwsjwGMtwQz7uJbmXeK5ukHO1Eq1Xn54JhZPsudtFgFIbQjaIALV/n36qy/bWpNz93BedHgzjOb1bgfUl970OHelGw61+LKb8aeUaER0oTy4YNRzUflyucSg6QhX7rb2L/6YU4aQjGR6cW46av8kHS8xkRJ7G5S25EDSq0YWIfo/3fqe4xNBBxeRHP21BaV39coeWrJtNNrRl14kqFtH52A2FWrfnnTzUGs0zk/R8JuhojHlHv/4RX9yzlciMJlpWrLThv+N+l2YP7pMCzt+ldvKFHA0e6PTzsisVIFvbkRaHY4yH0UeeswwMwSURtXpi9qBDUYiZZyOTvWKdSDRIv+JqfnsxNdt6XKXnfla8vcEn3Xs8t3itb9r/pUZtTIWHXwykyhgG8IyMihg0384t/l0hjSGji61Cj74n/aunjI/DUSItbaIbpLhScTMiU5Q0NmkD1rG/ml9LwuH+TR0zPUBRjRmf8PZ1zwBGuF2bq4E7QngD7hCcZEZGzmt0pOW+KyMuNmadqzXUbO7ryDnEImGtgE/OCPs94LITRCihPU0Xluey3/RwROo+2RL2A5Aov6V77Yunmxa3PJeLN0DJFkOxbVX8CrjCWlns0IjhKKWNyViEiyLeMslWj+QDtyL7METUbyTueVlv3MXMyiP7hJzUdpMzphvPj/gLUy/jL1EpmPoiLyOWTnK17+GLwc1IFYyno36iLNcJW2PhIxua0ae5p7QSyMC5Wexv0pJe7U7wPodaXIu2PcmvnIl69MNaAH4AGa6ou0MRrxmqmbdnVqBggnC3hIzGC1SSljHRKbv/5lTVqc6mRFSR5ElGPpYyUKM3YdIW21CKc/WAmGaX/OrNYmDvQQLyE9kipYCBJFDn1GBMOx81aOkAA95GCavWBxhLo2FrP0ZqiT2rg8/MiLJ9hg9N9ISxV7axsOrhCNf0id7y3paLiBy9Yxp6QAkVIXhnr/43j6Y1SCLltwg4XAn/g8FegMYe1sQiYXRINW1dmzpS6X6+Ar7lcpxf3CfrkDhkhRPXTiuvGM2SOw/w2B5A12e6SjvOWZPsm844Npc97MLYHIxad9dxwA1ahpZqvm5CxpBl5c5ASV9ZjLtL0rusUzDPAs27hPMmDrbLzqMfv3yPN5XA==","layer_level":3},{"id":"e89b1596-ff9d-4c3d-9c16-0200b89a07f6","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"本地执行","description":"local-execution","prompt":"开发DataVines本地执行引擎文档,详细描述LocalEngineExecutor的实现机制。解释LocalDataVinesBootstrap如何初始化本地执行环境。说明本地模式下的任务调度和资源管理策略。分析本地执行的日志记录和错误处理机制。提供本地执行的性能基准测试数据和适用场景建议。","parent_id":"20510b1c-4941-42d9-b461-571abbf86340","progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java,datavines-engine/datavines-engine-local/datavines-engine-local-core/src/main/java/io/datavines/engine/local/core/LocalDataVinesBootstrap.java","gmt_create":"2025-12-25T23:45:33+08:00","gmt_modified":"2025-12-26T01:36:53+08:00","raw_data":"WikiEncrypted:XMvsRjFEcSrjMOAT9RAdm4xDUJqNA0c6dCvf4s28FYYI6pOseK7iyUb4g0skcTPR/Cujv4Va3i4xC5iN0HwUW1eaCdKbjHm7sM7c/OG7nxWhOQ+wacJhmy9fo0WJ59VamAa5IDnNn6mh3CRsdEwObNeu9jDUpzepdrP7cUh9xiL9WnLGrabeVaFU2+B+rinjD4WyvqzVpip9HwCB3OMYhAPOUBgPlV2AfFe6i2yk8dUh7G7pxWBgwotk6YSjSBMWveJvdCGTDjMkY+PpjlR0ljpckNJxwV63G3cn/Hs+z4qD6t/U2t1UUZHzVJUFhOt8G9VmB4BPAknZW9RbkuE3vxipxg3DPeb4WwKGHLC3ARI8lW/Cbuv0huQMhk0N1ZOrQ0pOQUqqQBVukLuGG9QB4TMXi8EtL0OHDxRPPknWbYvpgsKBadUSaSHggxb3Gb54mOeVfdDpFHotgSUq3V8I/r2k1bKocFIOigJtH9h3Vqw1ksg3IIAn0CV7Tvatqsb+OW8SjPPUo0Zx2vqb4bghcEBHJOjgHhefWUDphVjpbGuDJJgXrvi09owczOhdG5ZsqT0AQ6+t3NTSxilLH+bJq9oL40F+EpBTYV/RMk/lvssMQuJt+WhVbiCN3S8UrY2Q+RYzZoXdbwRSf/3tICObw523102wu+CzAG/lzgpnMpI7QSSFmUef2BzkSLls7g2Ww2VHsRVEcXlPHJLx7LA7PkM/7GsS8WGBJiYXv2iWT/ZV3FTnuFgKLXg73vuEpU0MChn+DsZnfGB9WocssL5zgvdWnb642eZ+QXaouFgBoIZrhngz3yNmeuheRSxt8xGqBNSalh75k74NL6xzrd4UVEIOWxGcr1fmf23P6/6QhKc6sY1zDXAwxTdRDeQaStYduR9OjR49HgpEhq8ae+Tf/6IZj5pQdraj4nJcYS6b1bx35DrEGgIDy4Vq3FpkEtmFzUQCOQX+tBGy8zx/pqFSRlScHb5jPbxCcEOLvrWYeBdkes25rpYqAE3uv4MgtBSukQWbQVG4DNo85oZStz61TxFevioCWHbX3Bwas/5hpuJW0I0LnNhA2g/BTqj17yKM5Kfwjk2dN0GA88PntGnt4aGhuux0JJkk6cNOfDINO1VA71nCPcPJG3AsprbRVTQC","layer_level":3},{"id":"29e01068-144e-4924-bf78-a196f6575029","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"调度管理","description":"dqc-scheduler","prompt":"创建数据质量调度管理文档。详细描述基于Quartz的调度系统架构,包括DataQualityScheduleJob如何实现定时任务触发。解释QuartzExecutors对调度执行器的管理机制。说明JobScheduler如何协调任务调度生命周期,包括任务创建、启动、暂停和删除。提供调度配置参数说明、Cron表达式最佳实践、分布式调度一致性保障方案。包含调度性能监控指标和高并发场景下的优化策略。","parent_id":"bbd65494-8a17-4b10-9e78-b360cb044f38","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java","gmt_create":"2025-12-25T23:45:47+08:00","gmt_modified":"2025-12-26T01:38:35+08:00","raw_data":"WikiEncrypted:ivdvv0AJfpJMtOYhVYIFX4duSVEo0gCujwQz10pkdTqx0VDDuvrhJj6Bf9dOtl4o4jklDp3zs5GxLX6P9pKDSytaXR7xNwszoMko4/0ESGbk9NcWbr3NXOMzocI98UrfT8r/jQoGTeuslDlbQ9ruN5KXlHHjfM8rbwNt2pHLQCSRt2Fs+Tml4B3S+I0033aiHcAg9gbGq9rMUogT1ZO1aj6Eaxmmu9LWLwoAtN3Lc95qzrehu/bM+8KufXEziB78ak1N9bRMRplgBy5LkJ+utZtCK+sVbM/0sCQD6KAb8wwXG0E8zsoX1gYDoO/vzvXFFlg0h4GQ7i8vByOaFSTP8+FIIubwPbq9V6c/von/L9KGo33Yfs1uAtHEVis9J+vdzDNGjTjm8V+3NpSPPEuBGR/CwaglHAFexsWy70nWbfR1Bu5FgIHRNkiMjdhjeDBRea3R7Lyjymmf7nlQjfPg8DaSOVIzGyE3hZa6f/n/1o+3vuQdSF012vWezmwgLrTilTaEAQlogBqTgdm7fSWpl+dxRrbTz6rC6PdejG0l+h/F0paMt/Ny01qcr6KEsQGT6PpOfk5wmV5Oj1UmdJAHCF48sKwVFfhdYGJivghRcd80/VIMtbcg5R9rleH2auAufnNx1NvBWv2FNBcpZxhfPTQHF6irWW1c23V0cDXBzLmbVGgv6Xtl0ss67ONrpJaLzrZF+8o48JADDeg+kx9JKFKh6QT1oavO4r3X/qFpjOiEubIhi4s2hIkxueeYMOvzFljjaIIP77wrsJVdSGCU+HGmBY5T4ELWh2EDR5anUMiAkEghcn4UMcLAaGXdZUxNY1D2vqjtozkh/kBYnkCQUKwdeXdIZCvoWCEx8H0q2kpaVK5j+p9W/pf7FdLMKZUuk4VplOSiHeemNzM9VmYuqIudcRdiMJkrbrY7zI3Lro7U+aMZuwWli6z0au7dIj1J/QEagYWVwhMZaGRfR4ybvOaPT/2TR8PfEC9cicGRv2o4uMNILK+FsHdIrEk6c5LczAnmpWA3pLgEPElpFH4xlibE6ZVPisrIhq/9xGK1fXWgXy84wzgEutCsxnLeEvIAQhr/wSFboikw1S8HjagK9w0Qn/S2v3eo02aYk+OzdVOPt6mzQVt37qjl2wP1wHs14QFuKopiZ1nL6rzA/krSm5OHzyb2/AXZSmdKs9UQ0gEuRbp0TaTFY4L2SzEvCzYuIyRkGeGlbea/+KxIUtrLCl/jvyO6ZEW3cvSJwx+Buq2fexbhte37WMjJ6/dK7CZn5qFTSkORkM3ru9xVtkRkcgIh+qvPRnzjmB2Lhnf0z0w=","layer_level":3},{"id":"b4f46806-f78c-4b12-af87-a7a7fa341206","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务管理API","description":"api-job","prompt":"创建任务管理API的详细文档。涵盖任务的创建、更新、删除、查询和执行等操作。详细描述JobController中每个REST端点的HTTP方法、URL路径、请求参数(路径、查询、请求体)和响应格式。解释JobCreate等BO对象的字段含义和验证规则,以及JobVO等VO对象的数据结构。提供创建数据质量检查任务的完整JSON示例。说明任务状态的生命周期和查询接口的分页参数。包含错误响应码(如400, 404, 500)及其解决方法。文档应包含与任务调度、执行结果关联的API调用流程。","parent_id":"251acb67-6d5e-45eb-b64c-94b11aa2ce30","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-server/src/main/java/io/datavines/server/api/dto/bo/JobCreate.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobVO.java","gmt_create":"2025-12-25T23:45:58+08:00","gmt_modified":"2025-12-26T01:38:16+08:00","raw_data":"WikiEncrypted:nTkpfshEncfA5prvu4ctOAc5LjO1GuS/8Xv8vsJd2NMsUVEqPkcSiePgKHMDQML6Vi8zpAKUrX4a/W4xGhiViMduIncJtXX7JbAXW4+LMTm10xe6EUWQGfu68ghsHzgqw6VbLs/afedE8+dzpWjI/iA3KgY3uqVaC3kNSgfSKWNDHCHZV6JwHZj8ociG04mveLO3THIUlRnD8Dz3c+yzj5Zwz7dizgLVaDz7HhRA2pm1JZfvuIo3a+s82IclMxz5JB/wodIvL7vJi3w8L+J4e4xaQlPohDWRDe4SNT9BCY+Wa/WDbDU9+eig/p+9TrQPM8EuGbZQdkcdvDoNVYGJjWr3clsSfDo9moXaCZkp0MGvUK5Iy5bbEu6RscIMs34cGmc4c56SCEHFUh9IkDVnp03HKstiiH8+bqJHGTP3j2sOAbdVi3Wz9wgtCq6pEGd9YB6Wmf4Z8GxMM56hv4TvEMtzgSvNrUmizHDsZ4hFpggW4kE0UbeAx8bEJCj/TNCqmoyB97GmOQrLg/PBSipAmbsZSzuBXY3xUl5eRSuBUkx1+FTRDM8JyeI5+bXfLxyLSx0goIQ1pgxt8y+PbsZEhnahbFyEaqLyR8N4N4uNQiAEQ6bC3aj93Knyx+YuZfp8xGMYO7KrrC9k9SzA377vu0aG79CyMNz9PEl0REyAS3pgKdFLELDnJZTnEGQmjQLsiVT7SqoOb/VjBz/5G1JFH2/AGEJysI8H1CP9UjCYFy6d+G/QNZzScTSGGDPLj9T/apIHN7dydjfPXpf3At5MbtrWAAbdj64tuU7hduSsnLPFv+TCoxlOTTPa6cKhWLa7jauENWF0mOc9q20CXP10p5u1TwIzpGBUU31/3zX7mTwLJMp4uuvs70MwrysiHbIotdrTexKaEdfv+06LeEC/Gokk5XbZCK4INyEDW/ntVOuGLyWQGHXDb9Du/Mez0Hph8anhDT/G6NzMAsXnv+G3ACvOo33zdGwqL85TrdbPef5fFfF+4bpMjfyaovy5u5gVYcS3dtQaWq+CYL/9t0Ql8qbaCxS5P76Japg4lmQ8erHelzfmf9yFZPsgCSGLs9dDpDwYWL5QzmvXD79aIVXsRNU908EGd9OVl0XtZ6oLkyltod+zwHfEt8it58uKk3yKqCXUQhEv8v7pf7ik+Hf25ueyeX7mfU0PRsiBsm9zG5qjYF1f3jCQ0/430bNvFficX/RUUlFVQ/Hz8Uf/Y4/H5qw4Ph89ny7zz7qSpTcARkuJrzNLFbTQFFhqeAGp/lHtESM3nmDE2S7Q4GKBVmYIAYzj1YA4hyyPhCVwz/uE3DOVXGSpBVZbcyl2BQI/ZmNuuWWYfudX4jNg7iWSDFS80/1p+UnAwEBmL4oKO4FsC2nOLrRqhoT5E8l8o6HwAIiW","layer_level":3},{"id":"a493ad0e-2c21-46e7-bee0-76a79ce38c1a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"EngineExecutor接口","description":"engine-executor","prompt":"开发EngineExecutor接口的详细文档。深入解析该接口定义的任务执行契约,包括submit、getStatus、getResult、stop等核心方法的参数、返回值和异常处理。阐述该接口在不同执行引擎(如Spark、Flink)中的实现方式。说明接口设计如何支持异步执行、状态轮询和结果获取等关键功能。提供接口使用示例和最佳实践,以及在自定义引擎实现中的应用指导。","parent_id":"724f7889-75f8-4bdd-94c2-bc5fe8255890","progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java","gmt_create":"2025-12-25T23:46:00+08:00","gmt_modified":"2025-12-26T01:38:26+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJ0m3CIz+jQemkgQbfXfNl2pXnQ5ND6B1Z9+EZOPxrEjXXLHTDiv2DYF4RkicBsGA31B8WKkBObAPKe0nYN+AlnXs6yCam86EB2GbQUNyi+hQg8pV6B1neCe0+i9ZCtRZKMVD+qvX4+ZNd3un1EiLzo4uJKs0cNvjlbgmDWIXKGyT/d7yKV/9wxNphBZKEUTGtxhZHUtrAIULxRUQCNUmWr8tLS2MFqKGcCM8iVsqwq+epEtkUE4upbuerHguDDtY40E2yHaMLEnuqzkwLzs3J40W2KhkdtkoCgXrTDmpKlfxJi+99KmZVRe09eF/IaHXGEusirlRXZ2DTPut7d7vFdPjrT8IzEgsykKRphuA5HhZ7wSjKK7SIJr7YKbeJbLC7O+bY67b3Bmbv/iQToQJObE1BCsfBBsQQqNjEN2+XymwcR5PUQYLEyTiON7Y+i2PaMl8Ttp+Php+sBSJhoc5iFg7toevTs/cRVFLo7aCxHJzva77BgA/0vF6r7pp1HwRwvg943v1Gv3uTT0sPr+3dca0taARXbZ7OCqXNhNv5LWbvH/5OZDfl7RV5v/HW4/6eq9lobN+E3QKT/WYrpNG+xqkIx1UGCIK0W0upr+zm1U41HWey2chIowAlbyP4rWRnKzdq/JPOoL+z2EgoprQKzgLaSI6XoOy7ThMJkhMv3QwghvJeqrT6i9+7u4iEmDJqwa5bp8b5nMEh5WSdj/iiBd+ebOSuGjlPdpAKRJ1Qgw/jDC/kiyZbVB2GqO0NpOs+wtSHSSqZ0XkJKULN27H+4LE4MQoC/dHIZMLPoKVS6rf1Afbc4hwtdIRlmGHYMVDwH3x0FlVVV3qWnC5IPBYhf1CgiKljb7cJozEdL+g0xb36tbYcmnS98taYeZ9ptjfYmaJQHXlPyDCJGzNQX20bZODL4uF69Znh17mVrzdoskcNP9oy9GIbSLOGZwNWix0zl9PYCjfEjG+VUq3zsAXg4mm6zrqTexHWVohFhIUoST1W1dAS5Tn+Kl8bBnhGGzTDCjSkj1j5/BlN+pGcvrVVAU=","layer_level":3},{"id":"b2a836fd-0bf7-453e-b77b-1e65b0b5e6d2","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"作业服务实现","description":"job-service","prompt":"创建JobService服务的详细文档。深入分析作业管理的完整生命周期,包括作业创建、更新、删除和查询等核心操作的实现逻辑。解释JobServiceImpl如何通过JobMapper与数据库交互,详细说明JobMapper.xml中定义的SQL语句及其优化策略。阐述作业状态管理、调度关联和执行结果处理的业务流程。描述服务层的事务边界和异常处理机制,特别是与Quartz调度系统的集成细节。提供作业并发控制和性能优化的最佳实践,包括分页查询、批量操作和缓存使用。包含作业服务与其他服务(如JobScheduleService、JobExecutionService)的协作关系。","parent_id":"ae9c4797-fad2-4104-bb0e-09c584c89e78","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/service/JobService.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobServiceImpl.java,datavines-server/src/main/java/io/datavines/server/repository/mapper/JobMapper.java,datavines-server/src/main/resources/mapper/JobMapper.xml","gmt_create":"2025-12-25T23:46:02+08:00","gmt_modified":"2025-12-26T01:44:25+08:00","raw_data":"WikiEncrypted:pdwjVISXLzlNdYu30kAaUlI5LWRoaBXK5hv+TVI5KuEpFDkIA/aqZSJ5Oxhqc0sYypL0g57HpVVyPiD1rWnuA04Jj0yxtFasFxWiG+md16WzSfRh6gmN9u9NzAPgu4FQlB4jZDRb1/v3l4fopRKi9yLeJDoqQe4uiPY84Qq91D2JdKYfKC0rkRLL1s+I7WlBO1+jBbSEDJuOwtjgqBhWB23Gmn5m6Yo3UTzB/M1RzBBN2NHM2gihtNDnTddgskcd6EGJbv4j7Gh7SDP1d8Kzlzv4KrbONvkgFBvj95KepaHSWVxfVPe4O8j7MfXdspTtkhXiH0Zp8H5ed8Plzrh0fh3dB5BaAxSALkESics2pmpex1gv7C+83ffpQOvI4gRYqi3sNudF7KuQFHjF8ZOFuzXD6tdAAhZcPMQcQ7TtFAC9gN0ReMPmt/BkIm3811Pd7TgwO3JnOEjq+bpcKYwyZ7hjDFSCASl6QS8GopOthmr0SLxDVPqACQB6VdBI9OBWzs+nrzoxORGZzewHp9XLR4fXS/ZqZoR885ONl0r3dDuajncuteZAZxV0eAIzOA0AYgktqRKrKJVFA//1nCokmq8ZFXGv6pzUJZvXCqV1qYqctgMg4uMfDUsP/Tn1Koa7jjj+XMxmDT16ufrhifYUIhEDaiTK0Kg9gWORAmO53UPIF25cSHlsqhPeexN8pB0uJYFnd+FfH4LawZXnLv4LJKn5xTA4Q5xmhKjRX2QyqjxV6wKFEIPsBv+DPn2mlIlbFa9qmOJ62nZj5w2NIG9ZLN+jHfTjYBO4mU0S4Df1qWHtLMWZgmhea29VG/dochyHK5kVPVBYSIolMOXwbPQBNCF3fyiivLGOcdReUPGqlzJCSMZpK6ClWJelGutXfxXLgykXywXlXbEWOJU+ujBl11i88wvvA8JC2FPgZYqEQ+s4VnvevOKHWA+7SmgKRaMVq/XLbJqGVyFjkaj+3p17+2N1l0HgSTsfXhcGoiJJh2Lzm4iXNTiJQ41YI2d+gj9p1519L63A+YZ4G80P/t3YP0PWBXZ4zQsKQVh/8yTYAwvXrstmxHpEl2Z00GEJt2/AuBZ1+R75blcK8d+me+2OVKpwUBIRXWCth1sROxIc1OUxavAuS5Q4Taesv0gZ5hUvtOJEkUvCg0nHCed9QTTab1vVl4zLyZYaLBFaWVHj+JLApsF7vHAQas2/LcMP/M0eFaiykUkabv9FpoiRc47hz9iRRWqRIrFuLV+QMGVwNYa5f1qsdxdoTaSxgT7CG/miL4Hhiy0zxDlck18Wk2pIAOi0RdMKMbpGKsXlE4mrw5sajUCTGk00naN3gdxSrF+g2c35AzMmbGMJV01mPw0AyeMW4hSZnRP8+mhBlROyvVpIO9HzAL2u/V1WXoEidVnnwo9m79VE+KXB7gwPEz7rmw+ui/xBjWxLo1efDMpEhmS4LmTsJY6DPKirlyl8yW62NUumAkIVqSYMqn5rjQEyeP7e1B3jRyBi1SKRFunNW1jGPeS42VbWdzipQ7WnJ4Kx/55ba/fAo288jrso2cYRZW9ykjFPW7DjttmRoySwYUli6Txep18DhJ/dfTadOqDVkIAqw8Fxc5p4WcI1qj3ebk1rH6jUnIBT40aTi2lkZ+k=","layer_level":3},{"id":"7f956d92-98d5-4434-8c9b-749ee8faadfc","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"抽象执行器基类","description":"abstract-engine-executor","prompt":"开发抽象执行器基类的详细文档。深入分析AbstractEngineExecutor作为所有执行器的基类,其核心职责包括任务调度、资源管理和状态监控的实现机制。详细说明其生命周期管理方法(如submit、kill、getStatus)、配置参数处理、日志管理以及错误处理策略。阐述其与上层引擎和底层执行环境的交互模式,并提供继承该基类开发自定义执行器的最佳实践。","parent_id":"07b63f3a-0384-4d83-9231-bdcd684fc464","progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractEngineExecutor.java","gmt_create":"2025-12-25T23:46:09+08:00","gmt_modified":"2025-12-26T01:39:59+08:00","raw_data":"WikiEncrypted:XTtSlPOdQRsbiRKpOCDQ7LjKCgcJkWNauAYjpKznzP+v7n8hB7K06STw8p4aJn7JyuoauO9Qk/VohUkvC7bOPVJREJvTtPk0LH7wA4NAf/L74m5miKS6xoBc+oOUB1mv5zyvntIbD2wKk6dnhDjZPCQgt1Ggp5ZUjU97ldS1rr7ZpAE8qM4meiKsPleNVV8je5TzjRlHliAP9i+8e01Xgj3bzuUNPV4o4tWbq+YC97OHHjrKDFDzXFvovyokJpYjpKciayyEFqA9wS8iMrNwgP7g/aLzQtWYlig7K5hfs4yUN5yqJU7QXajnlV8WjxZr6/Fliuf3LFrrOfo8ieazuy+m7XqH2kgzrYydNDXpsDsfAkLB90z+9GRtBH1SKhTjoO504Xa6IVa5GwkK8MnK/zxvDIwL3TckFq3kguFNFJuAmFDVDDLCYyo38PZwEEUDNMBdrO0C9ufr5SLs9eX8LAJOcbEo+s1QMlFL1x3/pepw0U3hUb7xdfQn4V51Rxcv/GCHzOXGugB8qpMPhBCUrO+8q0TQ8+9x+vf8yQGH3Kbg6ERPW+17P8BNs2PoeD8XxPBJ9ginbWJhWqaK5SpQcxybpfrW91CQui2cqM8/xveMbIjOeDQHGltv7mtzMppTyjV/wCeDYwB1+Cn+M8Mb8DRZxMk/9yG6OMWJ/9DpSmxy/GC3TOWoZRGgnOJySRNceFLu5Pq0pUn/eXWTPO4+Z4gZvWhJ0lRbb5xsKXPaiy7RJKumWj/cXAsWk+kiaE8v7mQBg9WX6BmHuL6EiV4YezHyKBjyP2uy7v3CKY4QTq7SaOAypMvOExgkX7uN/nnsZo5tTNd0OrDahFDNIQ2hOFU+Nx4lxeRW6NYFny5J9rpSYqHXcJnws1dVNSpIJZMIblLMpPajqj2MgjmyeiHV3EnbDKKS74QGtXrxdHHy5tdAgTDQnypysEF9ZfFXuV9bLjYVa6NTqp5oy9CNr/TjlqB+E5/HjlZ+KM7ZVmErhkFnp1gqjoDwU+ue8HUyadyE1FhrsPzQHoJCpipGdm4vbA==","layer_level":3},{"id":"8195f94f-7c42-40f0-8e98-ab1163cac8ae","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"单表检查规则","description":"single-table-checks","prompt":"开发单表检查规则的详细文档。系统介绍非空检查、唯一性检查、值范围检查、重复值检查等单表列级质量规则。详细解释每种规则的业务场景、配置参数和执行逻辑。分析ColumnNotNull等具体实现类的代码结构和关键算法。提供规则选择指南和性能优化建议。包含复杂场景下的规则组合使用示例和最佳实践。","parent_id":"84f45a10-33fb-4d11-96bc-c2372db645b0","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNull.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnDuplicate.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnAvg.java","gmt_create":"2025-12-25T23:46:12+08:00","gmt_modified":"2025-12-26T01:40:43+08:00","raw_data":"WikiEncrypted:neigK6RjqTPkV4w5UD3v2yOEpIwQ+hO599jGFdW9GIkShGphR5gzzqS3L5mDc+3ntLTNFIoCjwmPiJItk81EEuL2GfwElva2icM7aJpGY9K2XbESxoOqLlZBcAuci7/lKyIJcCGuYvQXxh3hce+GdyvwpG4eY/CcNgGu3+E6VTtmpSDs47isyVNqW1UPsb2am1v7VsFnZDV79+3UhxC8RRFq0Y8Hg1Gq30PpVc3T1b/BmywRQL0TKFoahSKn1ThzXC+FyRh8T95uUIlA1oitXJwGQ32nzb1Spb93u9HVTwwURY0yjPNOrcxYtdEUtwZgaySHxIr4i1FUyeEIxD+U0zza+l9zlFxXzoZQ9KspOyhsc6WroykhGmpAyv14dk/Ca1eLXKpMacV3FhaGp9v0UWzSzgw+d/qhAxenq1yxuO+YN5sVNRs9/ECiaZpkYt9fZosBMUW2f8cFXa/4TpMsQVFn8UALByuKcGJb48LZZIyjYr3gga77bVk6JrW3jqFguJqR0o1Jh1TPyqyhjQQclmpOz56gMj8oUjfic+d8JIP4mtBC5bjblYmNPbsRyllStHKdYTp1S3ZLUtC4phersssi5lKmdCQgFNkpJswDR19+H0p5c7wAb8XmULwroauWh9ugpycOMuArqtiYdKPpTlZHGZExGQqhPF3gBU/j3A504S7sxwT3ZNWzHM3hH5w1BMpzp3yOJ1H1RHNeTu+tdLETjztItfBYFm41C2adeP/uzs1X3UigZCUOtPxPGCgvvEUZS6m8hH8m0CYpK3VkO9rmoopZ+vcF3FiIM7jgwW0XCWt1dTRqk5P5uoHiktFHDzwzG0ktCyIbj8oasbJXQ8g1bMCk1RY3X+VDvWH98li+GCPBa3VSLXpsF/BV2AtIfMX4mLjj1+BidN0NneJNT+72xZlEojk0RyMvSH5XJN3fnJLyy2N8Yh6kfnEIIlQB4oaahL3VdfC7DKTRfbtK3OuAxg/6hCcVrg+ravPFGhLRUML0acUBfwO5wkiXjMmSLq1q8vA9GESGhIxQ09lkbXJxoJjkJmUDFpB/BoGQtZ355R9bl2I1/Lqq8NBIjOxPRbq2q+3soDziPQAvh/c2VrRD6DytrGDKSTBIJyxzjlMESLbB1baFJDIxmxsABgEIFCv0jEJYWO4WKTzk4jzVcd8To2sbpUtB8Nu+x5A6Tt5ujErFUlYdctQqfp6bBrxAD7LSifC4X1kz7MHOysDCp2p+TxMU0soU3/8XupenUiweIar0mYy0+87aFYnUHSknl2MXWOiUircPTLM4ndtMbKuyNYMMrhp3usCI200kOnQjT2Q27Qupwe4HhfBKNsKRVyoiwgYYlbG3clRkX8uS7ysDdUF+Oy4U/uwYwlpHujNL0EaZUK8fkggyIbkAjqWn1ewhRwGXiDtwFJR/FRTrzwee3SRjebMFLgAAKt4yFj+IdT0UrcbXBtVOv4zIVNT1LoMHO6OHtOY6E6UqK794BZ8pZ8jmXe2/v/xuIU2UooEAypuWQnGRBHWJJy49gZ9D2akJQtRXtiSQa29FVmumgUb2Brls6Hvl9wOfA1wjI5FoAohnU9G4lcSvJ3DBoSLjDTjcwXPm5L7payqV0ZQHOQ==","layer_level":3},{"id":"8b327b52-c92a-4f28-933e-dbc7ff98d357","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Flink执行引擎","description":"flink-engine","prompt":"创建Flink执行引擎的详细文档。深入解析FlinkEngineExecutor的实现原理和任务提交流程。说明Flink配置构建器如何生成作业配置。描述Flink运行时环境的初始化过程和资源管理策略。提供Flink作业的性能调优参数和最佳实践。包含Flink Connector与DataVines的集成方式和数据传输机制。","parent_id":"aa8efb1b-1c99-4fe2-a451-746364c7e416","progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java,datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-config/src/main/java/io/datavines/engine/flink/config/FlinkDataProfileMetricBuilder.java,datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java","gmt_create":"2025-12-25T23:46:19+08:00","gmt_modified":"2025-12-26T01:42:08+08:00","raw_data":"WikiEncrypted:5ObXku8AzOSDfLk4OSAc/pG0dyh7Ft0zODhl2DjhieJMRVBk8dBYd33gFULuNh8A/aBkmoGiFFvN/nZVsVAxDLNisgosdst1u9HEtGPJozcgQ7g/AMBjnjmN1L0wPFQrQkcCwKWPqQNO3NPVMwts/1vXFzPVybYb843vcCT4RwDsiPatryKxxx1JeGyBPOWwYJxdkajTdxel898EjMO8BfdjPfsk2yrqCO3XZLno1k+dIp2szOfclcjMHYOFQzjPIcU3PpZiCgWBZK3Yfa3K+vYOjzUKdpICtfvuZKYGZcHruyD2kQGNWc4Tf/dG5jkUuGGLQ4NnSOYONC1tPZb+k05j1BwEyHs80tNZUQo+vPeFI77k39LrXIlORF83mlPkCgTPqOTsMj8iXMAB77VE8bm3XKJbPJxj8TOdNxHFteBpnwlHqwnUyTOpicu04Gsu3ggddP2oEnfCKIclM4v1vV47IGbsAmeQRSHajnZPWgH3GYRMyp1TF2Cw/OdPO3CcNJhW66Pc9Jxj0w+l2fGPRCxDcWONu6Fk9l8AEPlIL62A9fdljpkHAbKnxz3clVWuhHVT9u1g31/oSjlbvoXIKCaX/ZTcUzngNc4Nh4J11JXCeocoYUpmRQ//Srm/VyezQLlHEnHFQjiOuVFwI971W22cFjrE1ClM9N/dMGTae6hWwNU/TLG2o5fnHL+kNHFSc7yqm40kDEPgOza1tJacmvOgF9TAK0BBNxSR98W1RPQ8/XhbbJZeR+sp8qjKlihzVycmScGIsI4ZFfwEWM/rJUuxtI6+Zz3AuN8KQwvY3pXKU0HzkrpGwgbiL3YQETSE8aZ2Ae0aVWAYl+6gjffTCXtGY2LNG1Ii6UygCY78bWEGhLogue4o14ARD3tUDCyjQiriGRqi7NkyJVQHjEm02RTylO16cisgcDd2/GZ6jG0pzD5OOBVgBs9Izt8pt/2kTzMYo5mPK7pbAeh4SBArWtbgVw1GNs7qxko3tmsvjOsXz3oJzD3jJws4EikFjz+HFK4IA06p9Q6hhtqKxggXvghDj3gJx/cwmetVM1KxQj9pW6i3kCE9umvThp/ynp+U3VQSYDNa9LSMEqrZ6qZwCXuX0HdsvNI3XE0fF0shcSGnsnEnxrFgUFFgLWFmMWu5+Xs6csAiFCAFNpLJAeOd9EXgq6oWhWw3bq1xWBzSjLYQIGr0B6x4IPZNdArVlFsqg9gBNlyGs0/VvRI6CgbnyYnKVCQlz/kqAppFCkFlvDu4sqauO/Tn0LwWp8qx5kqT4Q9ezL4mgTLFxzlPirnGQ1OOKD36Ydi0SnrT6ux3VjLdagytZw2Ea9LJKpdU2nDvmG0KsMVJKX98cIO+H6ABTGRapIZcbHIqHfaRZnWnkGq4gRJbf2kOEv906Ob1t2Y4","layer_level":3},{"id":"674fea1e-97be-4cb1-bd76-900dc70b7b59","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"固定值策略","description":"fixed-value-strategy","prompt":"创建固定值预期值策略的详细文档。解释FixValue类的实现原理,包括其作为最简单预期值策略的核心逻辑。详细说明固定值的配置方式、数据类型支持和验证机制。提供在数据质量规则中使用固定值作为预期结果的实际案例。分析该策略的性能特点和适用场景,如基准值验证、枚举值校验等。讨论与其他动态预期值策略的对比优势。","parent_id":"a42f354b-55a2-4356-a7b4-d94e20a79fea","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/FixValue.java","gmt_create":"2025-12-25T23:46:23+08:00","gmt_modified":"2025-12-26T01:42:10+08:00","raw_data":"WikiEncrypted:BH5kNTRaf+iuyrwr6itH7hYX1kgERZ70nTRQFQDJDe+xh47FFd8yqAxcSDVsaVsPya0HhO0eHcOq5m/2a7SJjMOdn73387ioctD8WmsmUrtgkZIjiLqsNIWtzOZhy0kDNcYMePWOXLRMgM9FpZs04+GiFfl9YAzTFUtb9OaL06P0xUylnaBmPPBGlXd6UYxxC3KGGg+Fo8q9XkBdEtEgwWtkxXvLNvNT/Sx81xaRV/RqIYIpayhEfZI/Mplth6mNJtQKHAJqZi3Qr6KasHOP2xsduOAMRUJNwbGDFzxMBQRdgbng+JBbk1dyaI4Mixp1r2GAWDYpkrwWLnadhPbq0OC43zVF/LMaMrK9f5uvgLHQnnVF1kTUwjzGOqtwUHolkWs9IyZvjMWSOb94FpetxGtZWyQKCXKYXavNZ+kJLiywTeapg2dCye+GuPm8J8DxpKGguz+xlIAsaShlh2gK/XdUlzfk6eg5KZwAkAPt1TCS+rNhORykhXv+hLRRM05zvRKODqubNYNCsjMZN21FiAGVseESoHR90EY6nB43aSqu4udQZaRAg2DOMHd4UYwihD6BnJja+EeROppZrSv5osYpoD2iPCOgpyPXRubA/UHnokl1EPNOnbYEYrDSjxqIIN0YzuWVIyaslqzuXcQT7nlm0eVkqXEnSYdh81PJltK4EnHKjoULK4+SF3VOHxZwlm1QWWjkQT7j06GNKR7gow3WGj88TbAYP1i7Z/8CVY31tMPknX1vStQbdeUPum0lu5bpSEBgkahjojtn2So41vKjyH+5LgHrxiruUMkF7vP4enWou6a0EKytU8SGsouUx4KO18iBGUSZ/qN06WwMa26M13N9RjxvyuszSgPftT/YW0nFUR8wkzt90Fs151XVgma01AhElQZTjT/0WWoKsTvSJMHfT8nZ/+PIWiQKjON18HsDtMeiN7iSOvlZbfNto2IxBqSyjCTTWevtk4zcRN4iiV5HTPLdZNAVdktMwqg1by5h/A7PokW4wVMoU7ghKfNb0w6HyLHFZ9Y0ciOFHQ==","layer_level":3},{"id":"00ec5d54-4aef-4a88-ae30-224227f025c0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"首页功能","description":"ui-home","prompt":"详细文档化datavines-ui的首页功能。描述数据源概览页面的布局结构、卡片式展示和表格列表两种视图模式。解释数据源的添加、编辑和删除操作流程。说明元数据采集和刷新机制的用户交互设计。提供首页组件的开发实现细节和常见问题解决方案。","parent_id":"21179d81-91c3-4822-bf9b-316332af72db","progress_status":"completed","dependent_files":"datavines-ui/src/view/Main/Home/index.tsx,datavines-ui/src/view/Main/Home/List/Card.tsx,datavines-ui/src/view/Main/Home/List/Table.tsx","gmt_create":"2025-12-25T23:46:24+08:00","gmt_modified":"2025-12-26T01:43:41+08:00","raw_data":"WikiEncrypted:I8cx97SFwBvvq6TGIWw1mLbbs43IUIh5vWWpQusH7U9TLbKMc0bs6hYgqVU/svuzYkt2F+xNnsvFP5MpSrG//XXvBLGXo+gJy8Fnp2QbKBpIs3VdNmyPbnTL4UX7QFEcYUKmcmbRNb3V2YIej7QjgAxtC72vy5GsotFfT+P2tclRnDzM4FErhL0aTqtGjqJxSCxV5bkBFiIoCPM/QtOs7hMJUsIoC6noFl9HsgXuo1FsoYTO/BokXVhRAcms4uyXdGeblngn8WkIvHh6VOaMDxj8hsQPQ91vgFcRH06UrjSylfYBjZOQWu/1ss4bSS11vFHNopw2/57+Z8FoIGlP1ApeMjB32eQKFYB/U8kySNkRpJ6E7UJzelbwzvQt/AWp9OKFeOw5Y7OuBldaxS5twTegQyKux6t725x02ezXjlszyRu0GDnNlY8X3r3IJD/IbM+WFpxtSUyjNkzadspBI4n/aSQX37RsSJmbEkH7kJi24jpVYx/CJHPXEFv27cUDI7WcgDKaCC60mOeb6qMuNI+6M5TPMrUtK9L85bmADOa4F5YCfgUBF+wV+HY5bY6141l35Ef1ItpuMjyZkNBkrqiHbgMwZFBZ97tj2/5wMK7Av3VhMrOXfdQJ+EjgPU09Tn/xL1q2WzXMNwvMzIAvQsZLELxWChCmO5YbHEMWlN6TzS+FusbFZscqlQgGoQRloVf/xJkFU1XXMA0YtYbggfbzxyuIhQYQc+8FsCezPMmKWmTqnv1cTw5uxIfefGITvbinkPO2/54Dci+hBRB8/gNtOjmCuSFT57SXrpIiFMIdpNyRRxku9DJIdTMXp3TbFzen8DewiCRTWiihfMiOxNxZBNcLYkbtrEWnKmvuKy8VaVcGENl9W1kR/6HM617oIg9EfxQzMoNS1baQr1pUyA==","layer_level":3},{"id":"44ca2346-0af3-4baa-80ce-b4d555126b9e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"开发环境搭建","description":"ui-development-setup","prompt":"创建前端开发环境搭建的详细指南。说明Node.js和npm的版本要求,提供依赖安装的完整命令。详细解释项目中的代码规范配置(ESLint、EditorConfig),以及如何在主流IDE中配置。介绍本地开发服务器的启动方法、热重载功能和调试技巧。包含开发环境常见问题的解决方案,如依赖冲突、端口占用等。","parent_id":"ee36f1eb-9d0a-46b0-b7b4-ebcfba792d43","progress_status":"completed","dependent_files":"datavines-ui/package.json,datavines-ui/.eslintrc.js,datavines-ui/.editorconfig,datavines-ui/build/webpack.common.js,datavines-ui/README.md","gmt_create":"2025-12-25T23:46:30+08:00","gmt_modified":"2025-12-26T01:43:05+08:00","raw_data":"WikiEncrypted:+Tc/Xz+2j929YuZLugMAo4tvCBtHdnD0N7C0hAEtFjf/VuWwtVGE/OVMnMZRIZZtJ2vpDgBfAoudwpFaOnRhkW0RtFQ2nAW1oS0x6jBdZ9LVqhcvRLilpyasexEtKcJ7/WcYziDi9DEqUBmPpDiB5MigFMQgycVSqcYb8a1vQRCgwc7SQwkpUpBJwvJa/ft72vS0oAr2OzTO1HsLoMrzaUrd+hmmOqY/2jFxgIQglB75C3QpABUmIrLdriYj01ZHhggKe0NS//UWmBqsH+we49Ed3DSWUA/MPO0TmtiWq7xa0OerdnTfuTBSgpKtP9LmaYlqCjy3XkyqdJxOuBPQP4q/lvM70g7RzJ2XPJseWH2JvDDjehm6Mj4WSUxU+y9qnnMwC9xM7mgbgW0RuaHSHNoS/hp5hDZiXFByJelHToybMmWvV6gsC+qoxmjG5N5BCgbooASwqmMHzTx/d5WoGnViY5wm4l+cJtphMZwaO9+74VzHPg6K13nTobO5oOoI6JWscK6fizuLKi6WJGC3By2ByKNqVG5L1KKKyFq9woCPe29g35Nn52oQY0UW9kxVYvQ1l2DgYuOHEBfuSGkvyKTEhOtglFVxln/usGW+pLbYB2uYH7TL0nhKt+XWtLcDTg85I7ZTjepEoU7NuD62zVwAvdP4MnevFYQ4KdtyUjQo9UIXSqMRUMQ/T1zyxQbD+D9b7w629vmjjl0skS3weYBCaxXZcxlcqxP+V8NZJQQCYVoFkqBhqO82zbcBj+KoCAsoFimZ31/pGDxFhgZzjdRSr2sbAKmurNKlDqs3nnRkfXhYEFKtAO3/rCq5JDQsELZ5uoqztRr6WaAFEC3jnVm2nqYJxcqvsqTrlwPADBZn8AzTo0FMez5B5y87mzs+uGfJ1KuUu42xc26B++6ae/YGoYj9c6rKJYxZneVw59JhCPo3K9f+AgvaM6py7LIsw6pojecUANYEVcFSuTMTNofcaZ3Qk8KC293NFolwzuHrd7YZ03CzEMwe2aeU9N753TZKSIlEPcmX33+E2YOcKLi9+vq0rJW2dTnAiR4LNa4=","layer_level":3},{"id":"b198fd72-b1de-49ea-896c-25e9c1c87ca9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"通用组件","description":"common-components","prompt":"详细文档化通用UI组件的设计与实现。重点描述Header页头组件的布局结构、SearchForm搜索表单的受控组件模式、Title标题栏的动态渲染机制,以及KeepAlive组件的缓存原理。解释各组件的props接口定义、事件回调机制和CSS样式定制方法。提供在不同业务场景下的使用示例,分析组件间的通信模式和状态管理策略。包含性能优化建议,如虚拟滚动、懒加载和防抖处理。","parent_id":"29fa1aa5-5021-44cf-b284-95390545e925","progress_status":"completed","dependent_files":"datavines-ui/src/component/Header/index.tsx,datavines-ui/src/component/SearchForm/index.tsx,datavines-ui/src/component/Title/index.tsx,datavines-ui/src/component/KeepAlive.tsx","gmt_create":"2025-12-25T23:46:32+08:00","gmt_modified":"2025-12-26T01:44:20+08:00","raw_data":"WikiEncrypted:xN69xsyfHUnwfU68aQhW4XXXh5D/mKXwVg50pcc4uCMR9g9TiKluPhxjAaJtBWTCy6FPn2wRnssSDEXkTrqc+1Lr6luIuw/yFoqEnerFr2b+0nxAlsB9oZQLMhcuaXN6FZdwwe1X8dRCaNECfaWTv/uSuYf/8w3bXmosaY61QxuUOOH7+HAtbmw0S5TqpeGfGMTEul0vH2Ri+rRu2869FWpr3np0P7+6OwR7CLgPhFBAGdJw3f3BN2TVfKFPlIPw0opG06l/fFvpPPQFD6J3MYx5tE46J3c4OGdVAMA04xEa0fAyNHMWsIBmL4y3aUueAWSj03SVzbIF3EHaf6SnvYrTIWGbwOW9qAA5vu5l/O2pilt70AcYEQZPBlFezvwMw9cuc5RUcuztFIjqBeFetKpsIG2aZKT5LH9bJL66tsn7Hq2Oqpdkdo4hi7I2LAITdYK4lwLQdHqzIPz1WXlSd+GRfNqKDsFlJNOry13LcJ5qh7u+L9QrGiXdFKPU8VrZv++94Ssp948zuFg94lEMEcnL0qKmk9T9Q28ddP7zxRKOc2mVP8FVb6ytxgIUNy9eN+UAxkoWQBEkoJknsHsmEcgxOg5cBOUgwnjKPNp30B0L+JngdXtXG1c1P22kBuz7M1sBSiJYFe5ns4xfM+Cvp6EJ1Tidx8o+SHMldIIF+AW7e1R9Rm1VQrpbS5BpsRlYInCx27Lnt6JOXU4TY4wZaVcJRKUGjUhyv22zvYP5g48mlqmiceXVjoZ1NkvpV/ad7zmeNJBHO1IMpCl3uT/8Wt5hsrZ4JoJ6guo/c0iN5B/QE3WriRu0GSt4d4Z+4jO/0isv/ROa2IgrCoW8yQ6tMfQ+dZSHA1TYiSKOhEzxAsrWJRf2bjq9a2Kh/0E+5OwbzSAmFFe7/GjIAHjTcJTMvHZu1OML2RjSgmRb0WHrRFHQHHMSkD3UxcVCGJAPm17wANNXttjcpYKQKG/18uB4K8OM92HgwuW1oqu8kGtLFRqQ9wSARwogqDdtHmXZf+wD+ZfC3KnhdPekeUrroj8VZVwKb2lJ4244LBnRAVfHTQQdGvMhGS3LZvh5vcvgh0taLKxDusJR+C7CxLAEjHokNFykdFqFDrLi3lzy/LI8vmDtXnqi9SdUit62tgKG0vMG","layer_level":3},{"id":"08b83736-30ba-4a22-8df4-995f1b7fa67d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Spark直接执行配置","description":"spark-direct-configuration","prompt":"开发Spark直接执行配置文档,详细说明DataVines中通过SparkEngineExecutor直接提交Spark任务的配置方法。涵盖BaseSparkConfigurationBuilder的配置构建流程,Spark参数设置(包括程序类型、Spark版本、主类、JAR包路径等),资源分配策略,队列配置,以及执行环境的初始化。提供配置示例、性能调优建议和常见问题解决方案,确保用户能够正确配置和优化Spark直接执行模式。","parent_id":"7bd8d8bf-316b-4e5a-a32f-786067c2d1ba","progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/BaseSparkConfigurationBuilder.java,datavines-engine/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/SparkSingleTableMetricBuilder.java,datavines-engine/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java","gmt_create":"2025-12-25T23:46:32+08:00","gmt_modified":"2025-12-26T01:46:33+08:00","raw_data":"WikiEncrypted:M+m5dxh8XuRtgpG2DvE8kn3QAzb86xGlY96fFhcr29bjlFTDd30gBPIrWhuehNCy3xmepawFUaB0reV1mM7CIeZzJt8ynDkUvX83hVXRNidX948HCEhypR/jYwP1EzlDP+1mbvCBR739KntsgW6EVbQSZzWkPw0b7EH70OkfSJ8a60mkRV7ioJm0rnWe9cDujbYBq8VyuI9P8Mrw6a1MTfp3zGcSFlazRxjV+WCWIeryGYbMlSWDW2FTfgvA1fHjdETxbVPoz77Bo42CNxI1opiCltvcnt3J1QcV/n69zoYi1wK1VM+/Rkhvom6AR4ExCA+SMKjkeC7yhqcftmQudcWJEAZVDgpjUHg7xJI135m/LP3WXuaHBegqy8sedglUOpTJkHRynhZ6hdB7W6Q6qnFOREq/HjS6guBIsksaInyor1DjRnvXEWspgjy5qaSBMg9kU2O8Y8PZiMdTDr2P0EutnZlJjCIxFhAD52gG5rUj1BonPk8NUZ16VB7lY8DQiIUJ0DMd5YW2CveqlDqgANNo37TUaTvx/72G3EGQh/Icj+YG9/pRkixQ5RzvylK4LRVYiHbD96S8IICanPYgW67IRmbXWOhJI09zxWTa8Njbc7D8q6sew5Dbs4y/w6hHK9lofnZTouZFot0Og95SKjuXQEs5To5G3OKA3WqZfrGtGjX59qmByabm3XA9VVHXvpOq7oL6ckAvDygClMU2Q0wB2SOVCkgZ7N/egkYFEP8GcmrKafzillpEyHSwHrEDY5ccRurgygXtro8vaFwpBioBG2iWmH6WBGWDu0Nenkn15pZfdtkiP41dpesStBEyeGFQAFPT55Q4fUJsaTSps9kfcuVZw4IUFRjzcmAzqINHOdmJi+Lmw8G6zyEDDxkz0JgYzmoOwbg6TFhsBBMHqRh56BFWibYYOqg/SqwaX5K+zhRb6ApvGTxI2uLK1rfM6V2JKeiiWY19aTr8co/WFQGd6dqyXXdEn2DRF7KdBW3+h8buhew7Imzxh6snQ/Wo5486YLpeGyy31LApBTYc58zgw1MiHILVzS41oHcQb5Gs9iLtocgOZiE8x4L2Om3Bwkek8S75SjRlS80YOqC+ZBtW1T+BPAMsP+jAM/zQdW/vfl9tR2Kn4BnJSc0hGGhRE6G5q7VKdf+oe27VEUSOgTsu+gdWXhx4LCOuul2/UOcDpQOPBHbjFg/TStJmVk/Eu0ddf1HGQXxlw65QFapLmSwKkz6pwvzZbV1rWSzloZKpC0kQXOBeu8AO5FPw1jSjjCIrj5uYeJCgY0NEXcrdGJNJev/sNepikN4X3WCW4rMvTyOgV8SgIGuY+H3RXCqfn6jv0Xezttcn4Df/gmWt5DRJ/yy+QJpuCUsbqB5JhYw/9SxJ/vAetYtQbSpEz9P9QNrc4XJd9sXaJp5kuW9B07fALOG53VztQiqXNeUffaAyFM4+pWo46/lF0PO8vhwIk0mZ9nFhgoOFvGRn6zO9iA==","layer_level":3},{"id":"1f6711c9-86b6-4a23-9777-f70d30f330b9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"YARN资源配置","description":"yarn-resource-configuration","prompt":"开发YARN资源配置文档,详细说明DataVines与YARN集成的配置方法。包括YARN队列配置、资源申请参数(内存、CPU核心)、高可用配置、安全认证(Kerberos)等。解释AbstractYarnEngineExecutor如何实现YARN任务提交和状态监控,以及如何通过配置文件设置YARN连接参数。提供YARN资源配置的最佳实践,包括资源隔离、队列选择策略和故障恢复机制。","parent_id":"e27cf36e-27dd-4b26-a11a-f8f2af97306c","progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java","gmt_create":"2025-12-25T23:46:38+08:00","gmt_modified":"2025-12-26T01:45:42+08:00","raw_data":"WikiEncrypted:U8/TpzUBIG1R7I+yXUCBhJgwSlfqig1f7yBiZet14WRqT8rRkkVX0GsQj7Ppak3A1ZRWoa9akwNxy6hjAdtdyzDNU1wAXMTFNYpo6J8FAGSrUeUZ1jeAZ7fERVVuxNTahZy9vPbWqwnkCNglAmq5Kw1l/fsxBNaEjBwwCMGk3XSu/SBVoGmMRAnLFu71A/MaM1fw211imSBuZxOahCdbSl/LloytrCOXmqUsQedbp9zguRb/opwMcaZVgLTN9SBN7l3L3DKxursclig40KkzfC/PD6Q7KuECQ68FfhUPbsnMHNMv+i0IdGwsO7leorFD0XV/Grk4N9O0No+CEpogW72nlGSZSd3pj+uQD6iQv86fu0as8xGByWGwc+D7+Fc5crxBwxkI3mI2+Fiu/147XHcuz/dY2G9XNs060HZOdJ7ExVL2iTAlUP6gWtElNoJTMRwHVlscqpztF+Njsg4KkjpcPAwB8+APpXSLhQ9/gro9hDkCCYdFRMErtZYCOQzFc+AzRjyIRepfmkmkS/rRcAKU3uv5ZmcBM1ua1wJnEgPTtYf4BwlnR/4OPSz+vqaTnEPm7Ro1+u6OlS4jhpcRjD9ahZJVKrkPhkJnE0OlYrd7uK4HLQLSMq1rNKEBlNmHvd3l4h6FHX/O02Wtzhn6B3kFijjIr1bt0/CYVrLeuCkV8yybrJexTEjaA0IGbUYe2lDRuihnOaJ6EQwnQ/h/YFfNRywjvEeaA601m0VUdqUhFIpOeBS1U4XEk52cfV8M7LH5wFb2N+kFQ989F4459eKQpvDMZUejSHT9tnF+1Rvik/gDPipDxQrzkS8lZoyQ/YmmevkOdwrYTB7/XtbNArI2r6YNuBk4vOEbxDO7sM7qoxi+jESFjAvw+Ls4Sry6nYvMRDpUDBWYI+xqunW66iCObXzLgBca1qsXQgA43frHrm2HC6mn3rCRsYWARBtMSRENIdy0uV9kV9QMoFY0eEpXmCRtTGZ+1MvXFJhViHPhfOd5I9sGuuT5a9tzbNbW8Dxgc8siK/lINrhQQi76NqI2gb4T867BtkA9Ktfld7QaqLB7SzRjN3KrLyfq2fe+","layer_level":3},{"id":"bfba18be-d14a-45ce-94d5-f1f20d8eb9f4","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Hive配置","description":"hive-configuration","prompt":"创建Hive连接器配置文档,详细说明Hive连接参数配置,包括JDBC URL、数据库名称、用户名密码等基本配置。重点描述Kerberos认证配置方法,包括keytab文件配置、principal设置等安全认证方式。说明Hive Metastore的连接配置,支持Thrift和HTTP模式。提供Hive配置的性能优化建议,如连接池配置、查询并发度设置。包含Hive连接测试方法和常见问题排查指南。","parent_id":"860d9985-eb7d-432e-a1d2-69e59ae12cef","progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java,datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveDataSourceInfo.java,datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java","gmt_create":"2025-12-25T23:46:48+08:00","gmt_modified":"2025-12-26T01:46:02+08:00","raw_data":"WikiEncrypted:cICBKpGgTpGK8tUTADCA68sTgw4BYxzf+HgZ2J7cMqTy7PtZdz3jGkIgiWdqO/YHIp2+WV6Rvkc5rhfMyJYi9CZpbnz2ZSX3SYFpNyfJ6EEqfuRc0BOBdt3atL6iDU1JVhN5Ud3nj/148r+JiuiaP6G4g8lepW9sneo+7qzPC+lyV3VPvxuhzjdHgib4No+pox/imoeYNEdJDsxFOe66xCyFBwQD7UwhwvjGg0QSMhfvkiGjcyOZ1wAyP4lGCVYVItofN0ZXFX8f/pcJUDpuc/oHw6MUZ7FSbyq4ipol4nUR3dD+o2OK1tRQGZtQenzSIWdAqm8jEj3gCXuT2wS+VMo0qf2F1/eAOxbbcE4ezPmoSt/qXaewLzpvvsLS+oNaOas2FQjXOBwxUltKwoPu/r7lkGsyIWrFfXTAB8Xc2CoxYOW59YvwcMKCRpZTY3jgROsU468Gcx4+yu5CvLnpwg7iNuiOY9BvqYcpHCC1aBd6GnwIGmCFH26by5gNSIxw2Gx5NJNDNmeZQMBWDkc42IDdZf7+s84NlWUJQpMcV5fhIzW2ghwDJd8z99Dp3RbrcG0FRWhGKZl2p1WSkY8ZZbdVWuTWobpEXWeZNAzDJ46o2EiAqvjfY4FFjHapds1jug3hB4IR6XPcIkWhlljW3fgusXd2kmj/jk0W7bnvZPjiTZLxm9sgLLPfA18Ctl4lrpFqNbtTRJu9umYNHVU/qinceExIVXCkfJVlSxmkQBbqqBkJ5WAPni1mqbbQih1x/yZ+l2vQNRWAb9F1SFVzBY13McKQ/9Eb6wyONa6Is0xTscD4CZzHn3tPdKKTK89RICxwEYc6PnAlpdtUcAGNBXOWOYTVZ+6KWPs0cpRJ0zp8pGbOW6NHF/6Rg1NgaFGm6fildoAkPE77qt5IO3Xwl1nj/ZX6ztIerRVc+MQp3ew1XOFJJ8uHv0I+CMY1Q5pyufko3u4OxkLVa8AFLhyqrLlzIelmLmjEmqdi43V8c3sJYM26Wvj8B4aVDjsOg+2JP0EocLuTWVnjUwPAvEypBJiNS9OdhdHLU0WPvVRO+O8T2WV/ipne46EciZoTuYSzxakWZNgTijMXklmYYf8T0Yi3g7m1k7IG1TKXHAuDU0JD2RNfPegwbLUjfe82vDlPwuAEpg6PCawQGyrTheq17W75w5H8ejvrY+EH8iaP6HbV3FenQRX55ilvjvCOj8C5552ttyHfMTyTJPdvBQGtdcaKeFp+/F35GgMg2kJm1KDWxvVvFT5qazRNt3w4r6Lih+1n94FNfWpNVrTHkcVPSVyU+XR3rratDk2zVt9Gq4vD6h4TmThsdt2q3BKUA/j0","layer_level":3},{"id":"14e43aee-442f-4529-8b9e-70ae58302321","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"本地文件系统配置","description":"local-file-system-configuration","prompt":"创建本地文件系统连接器配置文档,详细说明如何配置本地文件路径、文件权限、文件格式(CSV、JSON、Parquet等)和压缩格式(GZIP、SNAPPY等)。解释文件读取模式、编码设置、分隔符配置等参数。提供配置示例和最佳实践,包括如何处理大文件、文件锁定机制、文件监控等。说明如何测试本地文件系统连接器的连通性和性能。","parent_id":"1e6b21d3-ffbf-4413-b2b1-7835661a6c7a","progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnector.java","gmt_create":"2025-12-25T23:46:48+08:00","gmt_modified":"2025-12-26T01:47:00+08:00","raw_data":"WikiEncrypted:XMvsRjFEcSrjMOAT9RAdm3TdGyErGnLyqH0ijZcqkfxsAAuhQ0sASHy1WKxx0EWMCpgYSQFCziDhDfvqQxzVQlJoh3Zl6eE14TLUe8yXdtTHVEFcqI5pfYLGKXiO2z211ybL5a9qrzXbhRGe+tmmOPA5kjeBFGqJSjpnydQq4fqGxK14iFBtiforVG8u6s4UgJRx7Tqe4MMai2nwHBoHr4RE6GYYwnFAR7zxbHvw9IvW21v1txa3bVQ3xXuB68ija3ymSRbFp/JXG4AFVpzjKfhgRVogu5SxZtJ0g3fYrMg+/r8RL5llGBNI8eHbJNC6v+mj2+6k8H1QC4MGUO1lYXGg2blGr0oW1DlIwd4cGW8dnxyylua8S91ac7AitOJ18lUc7X/we+ekZ2HoO7CBR5sICZJnhoBl4GMcUvr9DikSAMIfpswtXzu2hMJI7CW+Cw/IeOUGc9LxjTkKzyokXs950OTFZljmzmyeQwZveqJ8YzBXUgvJYz7Zqh//ecKd5pd5/d8nf/lfu9zYos4ERXAWekaffQeejZo1rMcdl8lxJT/J9mE3K8sHtz/ndyniUAW4gCw1zIBz43EYJBedD25rBvFALTkHDBYIBcG3sjYpKCQT0JPMshSG23e6eEvnx4Vyf4YNhv2a4PUJ6AePAKlPhLn2CbDmMZACg3Pj66Hqt77RfvScGkVuQ8YpZFI9d18A9PAaPQqzSHKlQPPBa+pcbBF8ghqZM6q1fMGV1mxNk/aqWyDcQzfT/RbdJvmb4maAZzccTMtORgcOLqQPKnmQltfu5Hr3qk7VB2pApqAyh4hzF+AULgFRchm/G7+sFlfVYzL810WnMDzCYggRLDAOicjKOq0FrUkcPLpK74XuIbgU1/xlaZ08KwrNbePUtBjARldb/V39/Ql+iDC5bF1s07Y0xnJQWfpx0VKCif90MIced7uwHFUVhOE6JOM899EuKp9Y2+EIUQNDoPHeim5the9nZ12Z47vJR1lciapkCOAlFYPFlJwsXoVAgghw8QHDpfUJklb4HFw16DS7cMmVFNKMTyx5zP+lH5gVif/V3Rvx8KcRdEIviANj5+9D","layer_level":3},{"id":"a75a8336-b210-4129-aa77-27fd38e575c1","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Token管理","description":"token-management","prompt":"创建Token管理文档,详细说明DataVines中JWT Token的生成、验证和刷新机制。解释TokenManager类的实现原理,包括Token的创建、解析、验证和刷新流程。说明如何在application.yaml中配置Token的密钥、有效期、刷新策略等参数。提供代码示例展示Token的生成和验证过程,以及如何通过CheckTokenExist注解保护API接口。包含Token安全性最佳实践、常见问题排查和性能优化建议。","parent_id":"9a060c11-69a3-4a51-9fc7-0561602d8775","progress_status":"completed","dependent_files":"datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java,datavines-server/src/main/resources/application.yaml,datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java","gmt_create":"2025-12-25T23:46:56+08:00","gmt_modified":"2025-12-26T01:47:42+08:00","raw_data":"WikiEncrypted:BNQwBTrLoJXpxFN0JfaqoGrf/LvENqA7mN6ytTEWHqWxG+8J55LwXAOIwDtTVDfITkcgvomYP/eylf9beQcZyjCssqPL68vH6vJiDgunwK3jzIvG6oxOBz4tNQi0i+X9EhFPEKFR5Dorzwt27R63U0YpX/LQEQH7+47GjlALTSAViNzhA8TwTeJivmL76xeYGTiLtCKXI7jBICpH264I5NnO5XrWoXBAi91CBMjZPj3OBWQPy2bxqIQDH/EecUKFvJtHY0oBeklC06uQ2HBVVWBqJQEP+GN0JhCNeu5jefbMT1M6VSrcAUfyw27LLACJo2PtAx9s2J4x1E+BP39ZKCUWgE+KI1WgCJoBVfKXsKm4J21FmsMhOEEY45nvF1XPRFKKKCbeQZjnrqxgcwYCYioJIXTDMzgq+YbBO9qLjdB5F0vQXJbfNg4dUna+SHJ0hWuLoqO+7DZBWWeQ/1yoOzpdR4z4tcDkowZs0AhLA9k8bhB3r50Eu8wg9h07ZICOQ/LXGekbbWweBvr28fh+ZnAsuuHTGI8v2Ed40V1vRdmT26CGqkd3cupxlf+PWXshJaDIeSZPJxSvxkcmE9mV0ZP/GmebTAo2AuzjEclZ5bgqnQsWwWtaFnoMzxg7ZO4XG/XQgZYSFgKCi2OQ+QV1b9mDRG4EhA9z8SEA9dHImSl2sY4rVSLGAEtX7ruNjx9sTHoEpb4ra9YWLqvwP/jxfr0fN7ZC9vRePBHAo6eRcd0onBY5afDCi2LliCIWTAaXMy2Y34m+NGsGGC5Fre9NhXMsCGGGTk2ZE54FYD+qXzyY+ZDy8tNKk2sOxRv/gzy1SEUA2sYu9NxmDUOujHhlpOPLVHO9Vb0I6Ga0z8aHu/JomK29z8NEuv690hZCaG2sw05yalTDLcuIztmwMdQd5oPWuW7JmL+CgW0PDlPLZpQ68pXdPBJrUSnlp+D4V6XnUUIFIXbgDsKHK9TgqDR5W1d92P3FqJLHsE6TZtm1Q3BxDz3d9uN2kYUeWtHromqRnBX/0RC6T0Q6g0IAxV3k6EgdwToV8M24N8KTwF7IAs8XAvlO5ppGcJ24/i2Z5BaMPhGdc+rYNO6MgGzahHU8MG9COcWjotITBJ1DYJFmazx6c6ryguBQhGgOC27tAy34IgZcCQjKMpHqTU/47wQi5nqmFIpKLboDurk+mM0zyN+zVm267f681wpx0CdPtjLu","layer_level":3},{"id":"da32bc6b-65b5-41ad-aca8-56209ab4b5ab","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"MySQL配置","description":"mysql-configuration","prompt":"创建MySQL连接器配置文档,详细说明MySQL数据库的配置方法。包括JDBC连接字符串格式(jdbc:mysql://host:port/database)、连接参数(如useSSL、serverTimezone、allowPublicKeyRetrieval等)、SSL配置方法、连接池参数设置。解释MySQL特有的配置选项,如批量插入优化、读写分离配置、故障转移配置等。提供性能调优建议,如连接复用、批量操作、查询超时设置等。说明如何测试MySQL连接器的连通性和性能。","parent_id":"82e5534e-5b78-4582-ba77-8590166e6cd0","progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java,datavines-connector/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDataSourceInfo.java,datavines-connector/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDialect.java","gmt_create":"2025-12-25T23:46:58+08:00","gmt_modified":"2025-12-26T01:48:08+08:00","raw_data":"WikiEncrypted:jQUrujkvfnvWoK/AEAmZZHOWySWFjI1SYIjosKsvn2vtrqYUmdUVLLrawP/hVRoUpYe1kwJT/LMVlaTUSxn5DalAl4ie7o7rJ/22nGsbhD2CYaZ+XLqm2vbeftFB6YH1NMqtbVJwUWfXMJaf0i2zwt2S88YXAANjimHo74p3DwyYqObGHqP0iZ6SypagRSbXaMyH60EsVOU+yKhc6QK2nwpqY9LCe+lLVkA3n5Ncr9yVAyWP1buZM4do8/rTLsxf+ETjKXJUQbZYDcPBcjseUORIj74bA75/sbOZG/EoRjZ/zTbdxmSSbnGMXY0fGbjv2snBtUVaTlZ9yLxZ3n8aCI9b4S5ZSgkQxI428jpFcu5s3MfOO5DWPBkmwxEEQM3paA9LevG+XZvwRayo7epxlul/ugpwD+VvAQWnRp2hgQcNJj4pPNHRd4bGbixo0xCPoTs9csEqSP+WQsccgIWEnDGCsUvhvrv0eVd2D2JBhF0oMBz2NVlyJTnasJPqY1uI2dvaGaAM2vFIvFbjnPayjJzl99XD8oWxKrIuUSA3hS4BTowKMpzCZAdUDqyHee7bFjMQHxA3MWSriIajLzsbzHrbpN9tsC7tq6LSVdWbXgP4EIH97pgsnOapXyViUolRhsWRAHitcykY06GvHcAgm8PGiYKTMn8nHlWXXcf18Ru7lrISpAibvJnQSAbVrrPaxF7GVlVc1HiknlAquSwlS7MMcdewcQF8IbrHdYnAkNYpEqR/AEy5ID4X6BqcM1SI13kxp3dZ8hMRJVmMwqrIoyDNxxhSwz5ClmX38QCKYy8ijJNFytK1ED3EbdF7ItrddwtHqTe05sUhvRS0lcyjkv7iYkXVJ1SiBjkMSPu2b4EuYq4SB2PH4g1a2MmxIuGhEp+FZdivuc/cd+kh5qJordn61yjeTPMLMj7GZP+30GllTOq1Pv4ETrfB30qaGFeosTWlDdU1CF2+yvlubl53kv5rGpHxl3j2bdQkRwA0yU23q7Uw2Tw6cgfaSp7Bzdv56wR3+aN2QIRhUTfpzXpQA1qCb/R8SGyR5OnPv4HPknM+jkGDAJe68YUo04DIhAc0c+9XlPqCyJBHPwjo4QrkSzCDNAfEMcMDSB27IRVlyUc0Vbmp0ollDLGLJOjEq+Ky+Bx/SsJW6ZdV8k0D5uW508ADJTKEQi8Mhlx6DTC3/d0fq0eOndt1hA1ISZlK6RuvKDg8RML2AQJnK5FMLc73/Av9JNxiviCereTi4DjbMjCoq5453ki9TJYzgSeY4WDeFZ1nCnn2iUhyAZGkdUVJACyDYXgWd0IQn6ecDTu9Hcmqi9msTzq0DejCpCxV5V1yZ3Gu0o7PgMV+BJQB9WV7UNxA7WMi0tan5n2wCLlXJIl1FL10yCDk9zLTdeWNe1Ql","layer_level":3},{"id":"d0eec0e2-c60f-4a03-85d4-67f42710e1eb","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"访问控制","description":"access-control","prompt":"开发详细的访问控制文档,重点介绍DataVines的基于注解的访问控制机制。详细说明@AuthIgnore注解的使用场景和实现原理,解释AuthenticationInterceptor拦截器如何实现JWT令牌验证和权限检查。描述API请求的权限验证流程,包括令牌解析、用户身份验证和权限校验的完整过程。提供代码示例展示如何在控制器方法上使用权限注解,如何处理未授权访问的响应。包含性能优化建议,如权限缓存策略和常见安全漏洞的防范措施。","parent_id":"06284609-845c-441c-a8c3-f5d5dd0354e9","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java,datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java","gmt_create":"2025-12-25T23:46:59+08:00","gmt_modified":"2025-12-26T01:48:32+08:00","raw_data":"WikiEncrypted:be3GjrqSLBDPI36aNX7d20Sszm7KHblxSCSiFRQgptZkLJ1MawqmExhin2rhBynamCDXUyOgktFMqRff5556dClWEcgpVqwgSnySaOdmOXLUhW0x0/XBJsvmQSl6qt/egZIzjY7iUQVlu9VGy/jqNnbimqHg1EQtBnaQNsDv4uMeHcHc9bdonjfQRIrmmjaiQObttRz8urw0z1a9nnWIu3GYep5ScrqEGb9yLSkDUxpt26hJeI8GIPjtJ8JaSPbTIVedb3EpD4w3t1tn4sb2M9PK6qFWaOmIlSNhxEMbAfpNp/OHKGK0MsjNtZgQeaMkUCssaUzJGgUp6Axui4MHtIiTue1g7L1vVo4zi+iJcIfj9/Nc7hq0rooQQUnsPYqzxSTPgSXbwOIJ5RDHj8iSnHuRnjlBH7GIiSH/Av0ymyA/OdLFzhuIWTf/O2JkEvTZTeTHGdShwPYpbGJi8LSMnmxhl9x6ytqiU5vsxsR6W953cavU0XnOMbN3qInjKtG1RXFsAnuRja9t7A8xO94Tf8qU82WAojkOetPvCuB86AJP4eab+cH9kSsS2L+OngBAsgSvXdrf5w+/KYzYHfKJm+Bx006gwPlDQHsSrbQdhf5tW8lHUuB8Buwf6ut72Boaq0mMY9GEKWeJxpGIeslUmF4YtT18WXXxnqkLxDvuy5x3W6WzykzembWNxyg9mAneGC9wLDw4ug8ad89Y+Mkfbgiq1MzcOm4adKIlZ7RNnh3+qPcf9ie2WxYR4PgyxC7RC8cwTyiowbSVpzFZTWpug0GsQNc7HnkZDqTyEyeUQt2YAxiYRlhOZGojXyE/wT8wdOu8hEVvZilmedMiXa2rtfI/CFO2n7ExKVl2ufLnwaT1yC7n3T5E42HD+eUvK+GZMMzYZVRHxXTCDArdlh6/7UK7YYmVyiB/Jpm3BMId7dEaq3I4TMC2f9lbALAQPNnIt3vAfdRilneiVRRHipG3TB4PjlavZAEdwN9duTmhGtlAF5XlJrEU5tXZEt1gC2YYZXJZoAC/O7KK/Q+Va+0gISH4MCo9V4Fo5ejIBW2jSSJhxc583yeP2m2z8/i9b4MCrttTbogwVTGRfof+s0Rrt3afeuWTBg4zzA94CPcWy1Y0eubmpG1tkHmogSBrLpx/cmdU8zSzSk+57lCMBzhFPBF2HyJKxUVlM5TQPCyGXjDEO/al3CTB/JZ9s8k88/RZhe/cmBFqRl/SfQVdt7nQVHbmHLobSPZjANDQt/M8QS7KgPBTJkM6hCKO3q5pZRnYkBA2ANDCiAkIANGd43yc2BX0TPS1tumMuwLRfvucVGOO/RjHl2vVX0TlaGz5Mr6OfJVAOFOU1zJRwNIqq0hkfkgVyq5WeFOmvQT/w4l1xI5b7+BGORc3rL+1i7qw2vO6","layer_level":3},{"id":"c289c71d-0511-435b-9d74-e95ccb25ce36","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"加密管理","description":"encryption-management","prompt":"创建加密管理文档,详细说明DataVines的加密机制。重点介绍CryptionUtils类的实现原理,包括使用的加密算法(如AES)、密钥生成和管理策略。解释如何通过application.yaml配置加密参数,如密钥长度、加密模式和填充方式。提供代码示例展示敏感数据的加密和解密过程,以及密钥轮换的最佳实践。讨论加密性能影响和安全考量,包括防止侧信道攻击的措施。","parent_id":"6f1fa09a-2cd2-4016-8fe9-896c74cea65f","progress_status":"completed","dependent_files":"datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:47:04+08:00","gmt_modified":"2025-12-26T01:49:57+08:00","raw_data":"WikiEncrypted:Bk1wQ0TRVArLL6ArLjPCdiy2jR8eVF6iHVsmgnSVolanKspFZWTahbVcj6LLqV95BSQBdIxLtv8VXaoogtVXl0VsZOBJip9zF7Xfdf9aaY93A1Dky7J0Juvh0MZ7xsLXCZNPWBHbSSESvEWC2VqTaQey+uZgQEYwhmXDNa9DuNqQf1QvwQ2xm+eAnyi5Y+r+u2V05FDTwaDd+n0tBQp4SiahuI2hk/jCNnYSOhw8iIdAOAsTh1Kc1HnZ7kcInsh+gz2cKDQtar44TqH1uiLwZXMY2INKncilUz9reyEzTZiSNs/+JtfkY8TlaqbsMscazNYzOX2cgv6lXKnxIMFYNRv7k8b3vEybdqjuHX4Y4/zmv8CnmBnWweNEB6O7hrIjRkHRFTQOjWBl7tRSJw8BRgDscLI9B4IheDwG97qj1/QKBzyap1ZoQJh2aWEhM/e9H5OBLnvfGo6DuGhryqh48KUYO6rQFPSpG+mMoJglseybgzUdl3jpVosXGuCph99RD/M7Nxut9eQ4lcOR021fAivQ1Wm1sLz6liOf7zom34gt3oBZk7NgK67S39eVP/boYQQOR2aUF3Qrr8CR9D04rNOWmS3TUm06IojINpY2KRwkVuBcBtTM3SkxO143E558R709k+8chgT5O4ODldDg/sMDBT1ndhTA8O5zYKaEuznmO3hbUZ3GFov9vHrhdHcoYdw/v+IB5skZwH1xbFHSEv5yHwVW50IwG2/hd9JXp+E5gY9JSxmWZkkjRb3Yemk2DJgSrrBHskhCL00e8yzpKZ7NXJ5FjuhutjPwoF8Kbkt9Xr5isjkCEFMtNZY9vvMvwfg+gby2ctxN37R5PtLTEBbo4VgmklLdvyLLUgkpZspzXAWGd1TlfbBR+dM0Bm7QPRMnYH6cxvCtU/F3vH5l6uW3dB1MxAMT9cjvpWwENDQjWzVuDcAfYNn80uhh78GgBerWu2DJJQrHIYI/DVMzQAe2RkRyvHyzehFq0eNIZ78BikQOjEJlLV8ihOLM2A7FjSUQGjLVqdbPITXQlGvSzARDgJrtWQSvUuNYNlv1j/BXoqb3+roaFR4knAJmsiEey43hIpbxKtI4zCkXcWijmw==","layer_level":3},{"id":"856929d2-8ddc-4c0e-af3e-68de8ba55104","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"请求处理机制","description":"request-processing","prompt":"详细阐述DataVines中数据查询请求的处理流程。重点分析Executor接口的设计原理及其executeQuery方法的参数定义,包括SQL语句、连接配置和执行上下文的传递机制。描述EngineExecutor如何封装执行请求并转发给底层Connector,以及不同类型数据源(如JDBC、MongoDB)对请求的差异化处理策略。通过JdbcExecutor和MongodbExecutor的具体实现,说明请求参数的解析、SQL语句的预处理和执行计划的生成过程。提供实际代码示例展示请求从API层到数据源的完整调用链。","parent_id":"8686fc3b-bec7-4b41-ae35-31b1eaca7987","progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java","gmt_create":"2025-12-25T23:47:10+08:00","gmt_modified":"2025-12-26T02:30:33+08:00","raw_data":"WikiEncrypted:ZGBkpWf02wc2udcy/W652kANB78aZ2SGCix66ME4yKs1m9QxyIgH51+q+WjE95uf3yevY1klkWIu/s/jr4laS/kpiSssC4hVL8jzbBHd6/g3clyc4jKbHhB/0nN+hH0dfiJzkS9AeuU8iGXK6SpFCjmCQiJqfS5KnLklLgaKG7XdV/X/TYSepKU8S/+EPyX6549vKr+E1x82XzqT/lvprsGJE+bltHib6Eo5DMGdyAo4adH2kXm/m0/h8wwxiE5s89c7PvR/N0uYlL6cW8nPqD0wVvBi6kne6VHwyY9FjyYA4IR0bU2aygKBcx+pTdHHbfUs6L2c13lnrzjlC9x6rfWMN3EgpvL6/igq/xeHpnmvxz1e0NdoTEOux/PpUKQq3TDS15998XanIuXCqa5CjtUKrkx/iCjP1+1Eu3lwTKH65X955WA1xVURHVP9U4lnzhpKnswFWl7i6SQeftg9/YW44DyiXYH6/s0EVL9WT785iqiDvIQfjOksOpqW4mVyeKn4rn8fV12s4kTTk5lUkFsbsBlkEGYQbyVJNZvny8GDHG0QdLJmmlTfDaPaQv304dVyA6Rm3/KDHY7VBUOTL7QryDV03492L+voqTgcam+5rnMbN7x7iJadraX3e6ZbWGG8zXMZWt7+tSA3IyaSRIvH21NlEhhk5zz6c2kaYhFkK7ytYuFU2GOKE4LxE3EQ+xWnChXv2uoY8sly7zzu/nQnuVtfJC7kh5jJMVS2SqGbWTVSMGkublKwod2sgEKRq0wo06KNqY4FPs3WRAamftNkHGjvhVccsMCTZnKRgHSHsApPv15WOM7S/e5i+Sdi4xUT4uR9R+uO4tA8BwKzPByR/2+SxAkzZrtUJ8k1SMMnu1DSIFCBH4ZyKKtCvtZuu6/8Wt8QRJ9uM6WBMyZYqMv0YAj+xFu6n1+hHd2MoMAM0ZsbEBvFyE9NFHFteDROjJ8LAxGo1WD0v0rFFl1G4qu3XKKudolZCf6UpKWEsRC8cClB5yM53tUVA76MPOkyPGmkkMl/3jbpm7Bxe4P97qltRU83SwsstLMTY45AD+PQ2DYTn3jb48wbJNyhloa8rU2Peb5kLloLsqXURXio2kVfo+9vSMIIRpcbmJKZ/NV500hOqP40kT2msKGS2Tr8LJPKNY+MgALQqFnj4GSeWb49DKJl3zfJnpgUJvLGnhKpoEDZhBS0oHKVzbJBsEphfWUFi3xDUH5mEIdaqXTFgnd7xWBZ/3GE41jby0oGvfPP8FRPRE4ywOdF/oaMMRZveZWREugW+GzgzLJcAx3BaAzfYEf7Wib4qj/tsgEm3/0l0Nrxr9f0kEGgrTmPhnjPkrxTCL/UqOLM26v+Z9SVnEqGZt6M8JAhOuiVsOcWfZeuEu2yvHNfqyl1VNRb++Oq","layer_level":4},{"id":"2666064b-e1fa-44a2-8343-842479eb3580","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务参数构建","description":"parameter-construction","prompt":"深入解析DataVines中任务参数的构建机制。详细说明JobExecutionParameterBuilderFactory如何根据不同的JobType创建相应的参数构建器,重点分析DataQualityJobParameter和DataReconciliationJobParameter的结构差异。通过代码示例展示参数对象的组装过程,包括数据源配置、检查规则配置、预期值配置等核心字段的填充逻辑。解释BaseJobParameter抽象类作为所有任务参数基类的设计意图,以及Configurations配置容器在参数传递中的作用。说明参数验证流程和默认值填充机制。","parent_id":"bfcfc439-ddb2-439a-b44b-cc168804d1c9","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java,datavines-common/src/main/java/io/datavines/common/entity/job/DataQualityJobParameter.java,datavines-common/src/main/java/io/datavines/common/entity/job/DataReconciliationJobParameter.java","gmt_create":"2025-12-25T23:47:12+08:00","gmt_modified":"2025-12-26T02:30:37+08:00","raw_data":"WikiEncrypted:XrdctTWVeXLKnAGxKXAgOHL0Dh1UVWFYXe9GLbo22LMzgw3MDBZRa9T0jmyBz3w5jhQcw20HOLgjLiuSeUM+vz5ITZBonQfnqy5xVUcz3R805jW0eGOa4zpOjz9sXYjJE/HFLk5BKRHT6xkOny2RYASAG44FfXm1H989d9JVJr0Q1lZg6ftTSUfeg5kisHuXcSmpGl58fT2eJoEJnhtqB6/81jYvYqVGaKnBriGJx3aRYQKBpAyCQVEKgSsKrRXHFmXs7PhomCAz8AGKVBoi2qurRAS1ts4B7G7cTfoAJsitSnhqOODHYqz2Sz7yyJKdjyoWI8ouXnWQ1+rZfydw7fBXjl50lTvOxUXJoL8mFDOE6keSnEbvd+nY95+hEexU8f1paT2bax80lEa1/zjFgXJtpwvgVdegcGNn8+mcIfZfUqqGTO3QU8dJ60rJEvrX25jyv6YaJ/GAIk7BFKShCfOPY+K10fZ0diMKdEr4pYIM+fZyqx7t8DviQNDBgzpgcLoJvnZwRt6RevU2doVUxvWppjGCbDOc6pXyvZI7NhyRRC8EhV2skJsotlRSe44Qg7qUXBYD5nbztIvGnkbB63X662S7JqKOEcwSfcDwllODsNQ6haff5Ju6CYZTLHFtsjjaLXJKyAvd+emniN88j1cEUG6QqDVQd47EzOTLHj5b3Vp0ik6DUHHkUsmG/vgjTgsJ0bAuvSxmLC7rNhT24Bx1vY8nXCUzIhF+YUeAa6Cq4X5jPgq7mQn4gKtmrGMRiipCoyRoCcTgZpP1bRtrETV75uCETdfBH0Oss9d7rlc5jo0M9PFsWc7gjqIP86dEQV5WwR8p1Gao2dNMDzynN5jzec7m1HmT/kKLwXsjHZPK6m5+aFqzUFTj8cabX8HQhMTAraPHlp1hjCNKxSjvhdxbPO4u0M7UJ65UTGemc/qoPvpGmMq2BdEryz5T5byEtxkbwAeyBHyP3bStoNEjs2gJvwWj3vGSZYKRCmRGpVBN4NoAEjOUoRDomX4MB3qtORWVAWiU8ns+l8WwhyOpww7cWsvMWLtpFN1OEZnRoBZ6JTzqIfRUJmZq0kZxiWbOiPNG6+jOmkHu9wF51y/LLY24zUfT4+e+U49ex68zt2EqSs5niKM6lfQG1B/eWQ8V8j68KLlEbdHf/muGZPBS4ruysCws0XhwHs2FCzQw2EdIJETpbtQbEeKPm01C+0hCjky/QWfMcPjL8uHxj9LdTimXVmUC9LDBaLHsYnU+L70vwYAB8wAKIrPg8x61G1zRxJgtJj6MPN4Nz/a/eGpMcpSGemf0ol3WzJyz21lot3MAdFmL3OVA1UEE5svAJvzhMEgS2eg3Wm2zEIm82OY93jXqpRDxEn3o4IHDeP3oLkWsE+IULzEd3zthNw1SAmz+pArmz9KWCC43sL2H3kSf+fGCw8CsobUSeeGhPpdEoLTeKxOl+7xhdILpesiepkjPC8TLYCMLCsMPgBZy53wf6lDmMpEu9/m3VlTEWmo1WdebWqM2uJhqk/r2Oo21FIW3","layer_level":4},{"id":"882a7389-2ff1-4f8e-b288-24894ae6574d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"跨表准确性检查","description":"multi-table-accuracy","prompt":"开发跨表准确性检查(MultiTableAccuracy)的详细文档,重点描述其在DataVines中的实现机制和使用方法。解释该规则如何通过主键或唯一键关联源表和目标表,验证两个表之间的数据一致性。详细说明配置参数,包括源表和目标表的连接信息、关联字段的配置、数据比对的精确度要求等。提供实际的配置示例和使用场景,如数据迁移验证、主从数据库同步校验等。分析其实现原理,包括数据抽取、JOIN操作、差异计算等步骤。讨论性能优化策略,如如何利用分区字段减少数据扫描量、如何优化大表JOIN操作等。说明在执行过程中可能遇到的常见问题及其解决方案,如数据类型不匹配、空值处理、字符编码差异等。","parent_id":"8a7821e9-9176-4c43-ae8a-64769c6958b2","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java","gmt_create":"2025-12-25T23:47:21+08:00","gmt_modified":"2025-12-26T02:31:41+08:00","raw_data":"WikiEncrypted:Zt230nV3k3ww0eU+N8tTkq7TcKpfxWXNoyJXQd4NQoPYgsJXebkWlj1KmhM1v/lGapq/WcyC2KsKQxYV4bdK05+PJ9qy1Zxwn7t/uE7ii7B7oiYMs6xdznrTt9ptO3TpQry04if+V2p1mTxCeq+7AR9LJ6IEbm345wPFmLVtnhOvEaXXpu42CsB3kWeLF8SVsRFZx90Q8nCn9I0mcJzfbfvSYy9bFbac7WR4SARQxCezLgGWhEjraIeucgFmolbOc9ebbii6Y9nPGYyuaoYcGFYbcPJzWX/jm9UEn1rf0Qt/yAjDxX4aw+tdKcCODZuS9YwQNlBEtU4gIbTc3ngrsdhPP0D15oIJyk5ToLYITZMdPP3ftD9BASimInumDNB6DWgb0XJEbQmYqkDQUgVz+wAoDH/BIasd+rAP7Snb3AKDWZOH3zUe//8wFTYGLaF6LB7ErQyYyI5Hdtts9O6HrM1VbQRF6c6cbJK/lYQXVhGbyihYUJXgnZvtv/lyEP44UfoeGedVrLPAAjezVWsurHNIqua2QkIuOK+WQBm2H/8WPvy5lyMORbhsqgnJWbNv8skoMLIsXM25A4VvOhIf8NUzNKdcx3hmemPHoHunYFMQTtQuvWdSmW9gmWvl5ALhn1qYAWmgw8zD2kpKQhm+MPVMsqsSjB0Rzy+q2IOwY+dVISz85GMnBLzMKP1HGnRgU1CZoRDD30JoSg1+bUfqrIp4AGW3hi5VVs3HjLL3jemkWrMQ9s64onzwdbktNi8Ls9QgW//JVU3AtUg+nFmqxQ1Jl0VQ5d8ix4GQTfCsO9IndSf9G/gCCGnklDaq0SlzLIIYHV+DwrzlGjlXV29ZBf9i8DcAail1UjgtJx+A3BkNaBYf/cjk4QyiKQyi8HyeM9tMwNYoEsah3ZFtd1i2v8LxltxFXLUP1lym82zbX36plknhTaR897cPN1K1Kd1vekubfWeG+mvHzU1R5EIfEceLwLsl1FHwWbLcVmLxc2jmT/yDaB30y5qeafkWolYkcA7kO+sRB3306T34nLkFbL/bLnUpnx59nvC7JcZSu4TIoMqeajp/pSHMSVjVrSvMus8648TUt5Vlsl2hNc0qWM/o5fCE+B72+DXdvC58dA0ZkrURd/j51Jx7nskuXDpy5vo1G41ZZ8a6eECz14h2lB0hSviE7DP6ULjMs9pumoMcKgambZC99CBVfMxP7xFuxMNtSKpS9XvwaqsEzObyXa13WG+dG8daxm6z19PGi1GGmUncyXsCzHsF4Igxx9Xz0VUg5a5Lt3R9pOuY3fUBW5rgMrR1ouqyCXfd1Uvb59BEqHDien4dVyexEosildlD2s7SPu7Fpo2z/0Y2Y3ccv0pz7tW8B9iyKLhQNsPKgeMKFtPHlIotPM2srDJYIr1YyI1sLHMA8SKxShEck8zgz0wP8F878TkGYlkx45f9xEiwRQMqpuWvsBIS/4yS/vMBe8mcMa7vXfACcMEKROzJ+GI1XWOJHFAAw4vDvLE5xdKQCBgo7FczSAl5g8/MABG9","layer_level":4},{"id":"0ef347bb-fa3e-4159-9059-20d0f3a6427b","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行上下文管理","description":"context-management","prompt":"深入分析JobExecuteManager如何实现分布式任务执行上下文的管理。详细说明CommandContext如何存储任务的元数据、配置参数和执行环境信息,以及JobExecutionResponseContext如何维护任务状态机的转换过程。解释上下文对象在Server重启后的恢复机制,以及内存缓存与数据库持久化的同步策略。通过代码示例展示上下文创建、更新和销毁的完整生命周期。","parent_id":"b282f234-c03a-42ab-a5ba-d212befebae0","progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/CommandContext.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java","gmt_create":"2025-12-25T23:47:21+08:00","gmt_modified":"2025-12-26T02:32:17+08:00","raw_data":"WikiEncrypted:qiOE1k1TA+YNTXi1/8EeGvokCyLpa9H3YB7ZISkA8Zims7t8/AoTG88fR9BK28jaNdkblRajg+wlfZsNRDbcFBFwhlCiZ8uTCXdbisXoC59eJO5oisad7vlabsXqG4SAnAOjedyH8u5PC3kEsIXLKF0b7NcArcS2D0Lr/edMmmnbI0Ky7KpuPEDXOlatJ7oeyFXLI8m7roiPe0URiepV9nYaxfbeRnFErEXrfPt32yFCDqcz95oPLohjMh34OTVWDbejrGuqD9f5pE+1vbCmaHwDpxdjaix6b/slEviO+gekySQ/fQVpj2st9GWgTciDE5gaSC6nl6CdFaJd0KQ88nTvtx1Rbq2fA/97uDkm8dvXXDZ+15WlYNC4JZqj9+sxprZC8amYCxUdmduI4dtZRQVQ34/51bl7qxzk7J6zaNWkJW/zjdrXsf3biK7Bu9EIOa6Jo4oMmEuOAiifWDs3I3zh+KjulKmh7Cu1IzuCe/soRaL1ocd+7d3jpxjKHqKBSQnVFPSKCufZ6nCmEyURfNkJHuHXVZp6NWxiYbCYROPwhcQqZAOjB7Md8R/aHCtircpr172xNtDPhv+G4xNPdazYxB97aYkzGNZBTvn5oaT+c+blxLmhwSSPCUjcSEGMKgyHRCLdjdKU3r3EJ39iC6vI2bFCdJ4zItovaahTYeCcVfa2bmQILAUVsYn/RsgsD32LqzNFSjpkd7eGufwrptf36Jzmzb196d0XNaa7pJKkOaZc43XhcPr+JPPeWHmGpUArfe2NeYAUF0gAuyL3vE7/nmlHkRKz9FQ+6ct/qNpmIq/s+ffQeMTkc4z9ZtTAXhXFUgM0w6XhrAu3YSle+eagxRbr7cE7JVJmGXhsBdIfaxdloDjI3iV4ljWlJHM7ou7EvlfUvbOkKRpUkWsC8JyTX9d07Fy5QQCM/83KsTHHE2Wgfc9hTYiFR9gUrELyihvLcBWCo5xK9ubLo2F3k7Su3Bzx6m0MoJCI6Wjd53a65ymB77Yk2Z0USuwiQg1s6a21f/zZ11hmdsbKb4Xx1QNDjGG5iiI+VXAmHf/8Cdo9Jrx0CBz/MGH5da6GEGn8VbMaVxJOz738jcphXSjpkzNUBa3Zxh4DdE/i0Gb+7XvgAE1bM0TU7irN5dAui98ZwqnsFe8W4JItm2StIZK8QSV0WhhFtb/Htt2lNzGBtWHi3DhrsVJ8F08jF+IYRttIYLIBkA8eCWsBNpZe2GW4kj5Iyg5HVa9kVPGA9tD1QpOpU4ix/goGPuJ0wBDfUvNDV2vTqMA/B6zFtX1q2ZriN0ZO9QZSG+mdpSJ4vKyd/3E=","layer_level":4},{"id":"09f31c8b-d5a0-42f2-89d2-20bc6aa19b0c","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"基础属性检查","description":"basic-attribute-checks","prompt":"开发基础属性检查文档,详细描述DataVines支持的单表列基础属性质量检查规则。重点说明非空检查(ColumnNotNull)确保数据完整性、唯一性检查(ColumnUnique)保证主键或业务键的唯一性、长度检查(ColumnLength)验证字段长度合规性、枚举值检查(ColumnInEnums)校验字段值是否在预定义集合内、正则匹配检查(ColumnMatchRegex)验证字段格式(如邮箱、手机号)。为每种规则提供具体的配置参数说明、使用场景示例和性能优化建议。解释这些规则如何通过SqlMetric接口实现,并与执行引擎集成。提供实际业务场景中的应用案例,如用户表手机号非空验证、订单表订单号唯一性校验、产品表分类字段枚举值校验等。","parent_id":"0119e5f6-79b0-4d58-813a-14a0a719454e","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnUnique.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnLength.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnInEnums.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnMatchRegex.java","gmt_create":"2025-12-25T23:47:22+08:00","gmt_modified":"2025-12-26T02:32:14+08:00","raw_data":"WikiEncrypted:OVW48CGFh2rQaIE/lBBJpC/EMJLNx6YUJ+0mrECZ8eNuCHLvW3PAh1ejC99xThojyfOydN9VRBKQNgQhbSuUoop3lg3M+HdcDQ+bKCDaGSh0wmnJpuRYynnvOBgvJFVF8E9yBbik63R7mFCAW3oxZ546PLp533qE3QXFz8U16ULqe5YWn+HF6VKzkVx5s7efQkESlDMBR25yO7rZ6+ipOHi5NwmGzGFZjVG22K8RvhR5RJnPby1UGwAtcijtmy9k8vX96FTqwdqTU4bzihHT0/WU9xiXiS4EUmKU38qtUXVx12MDsQtPtCYnMkVoaMtXPbrPHNekuIpbacxJnY/Nl6oOUKfqkN6pqKVn4CFRKAH9zINy/NtkuLp3Iyqzaxn47aV63sCb4ZKuR4aaEl8braVAEcB83fsm+9sZy5dLhuk0Y0v7QtXD1HsiPar03yK1gaCTfIKF0nLmzNYvprsqJbgFXSd4l8BJd13vC+Gitm+njByGHT0xxrG156DcffHx6AMydYVB7H8GjLtjUFdis9RZ1+lYMIKqdUW/xfEFUyoTa2MZCmH08PLBRezE23wjMSVC+HOpt0BT+n5GzN+Cn6r7LcK9JY9YEx+zXx/zR0xXLJtbaf+Gf/1Bf2j1SqR3RsV8Puy/Awnvc6sifQFa7kFX6L5zZFEWIaVh/cZMiRGyLDOuiw6TocLbLji/YRn+kM16u77bXqbwJk1jcKiwERDbljUZWh82bEdr7vjNxFG4PIGSWeP3nEj/0bPDuyklpw5S2sDVfD2U2wYn9x0Mho+OWTPfbqyzD8LOO9CkxM/p9bIitnFE66AVlbJ2USJLDnpfxLl7kf6AYE5YmE33nvZADfbfdX421PkGtPuE/691hxYcEzeAJl9SRtf2xhgL9kivKP+wTCX44+Vtpq9LB64CMy2kHOtk73UiAJG7U2Q+TufjcGdDSkcm16AbVd6gzLMjIckzG5LLLxwfKVV0XpUEyOTZJlq3sYiux7Io7loR0lByVYlX8LnMYG244Ov+R2oKa3BRidLCGD8LAQOlf+naRrElR3bQBln9xBlv5WogvnoYU9o89WEqzGqNjvbLHKWT2hGOYnaql7CcMmaNsrWJpvjvV5hCSaeAmXLu8TL3ZCTkaHr9FdMo6P6bULgqMwUZ062XSD7/sfEai2X2x/9RdphegCLG8+kNOoHe3Stk2eAFj4VM9SSYIDNa4IV3C8Fc39b6+t5FS8p8gEu1pmdMQxxrytz2qgPRAHACV3vh+tX6l35TcW9fXW/PBfyW0exPD4Uj4GzgJbfMgTGpK8G6bnrEkarC69uvButtBffuNi7TIXyMp5MAMIoQsLgtStKS0cqiOZPyjtlq2iPaDyxUq3Nx5Aol3foOPZibfIYmxkoEl3Ix4FWwLsefn7Jq2ZDNb8WgyqA8/E/vzyz5kg+GIxe/THnqzLsOzw2L/+HbnycKmMMlDoZordNwgjk4WiD60GSoRVPCSRVfCxmzvZN47o98E/FKuGc7YlVp/01y9eMkFaBb6zGdaJ5hfIVUuHHddc4SYRcTBVPT4m2rCapUsElUhKY3ftvGcw8mVbMUJsx4sK524822VCEYdktFPzgkpOup+a6S+EMOYn5gdEZt4h5Bq1QUaqKLBS0hsmfC0RGUot6D+wGqrDaoDIkzTMSeidy4t9EcasDu7lmWG47Xe1lJPLvDNrlBB0KRVKv/IEDcoc9UK9tdjC3pJRMXjZR1vQCaEB1mqc5pRIHlnn9agjIPKBuRVHeVvgZkvLBsrkf4F7TCic5oROnTV1ZF0nF1tiWrcvmNQzPneVG4UbzXAh82lpcSmNCZyNVICMU1F3afjEslMt27sd89pOR30SnwZYPdZHm8TUAUtrv+cGyHyl1uuIzcZOfXO9zE9Tv8iVlHYhbgZ8PRcD5GKFFea90/bIxp3iiic5gY8zX9FznWYoR/vDEVEcn7vT0ne1Ga0sx9ByqFnD6AEJlH0l+mVu1An0LftCrHLNOw4oNSS4dduMJBMW6B7w8jLaiLc9GtN4lg61PFdqnNKLg49TUWo09ilphUJQ+fIa5jk86VXpHKztScb18BJSuK7vk/p4u57WoD/Kd30EWbU4sPkDf5","layer_level":4},{"id":"7a1f4b3f-875f-4546-81bc-adcfef66aa39","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"跨表准确性检查","description":"multi-table-accuracy","prompt":"开发跨表准确性检查的详细文档。解释其用于验证两个表之间数据一致性的业务场景。详细说明配置参数如源表、目标表、关联键等的设置方法。分析MultiTableAccuracy类的实现逻辑,包括数据比对算法和结果计算方式。提供配置示例和使用场景说明,以及在大数据量下的性能优化建议。","parent_id":"03c2fc14-d1f4-4beb-a517-abf842d366e4","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java","gmt_create":"2025-12-25T23:47:27+08:00","gmt_modified":"2025-12-26T02:34:34+08:00","raw_data":"WikiEncrypted:Zt230nV3k3ww0eU+N8tTkq7TcKpfxWXNoyJXQd4NQoPYgsJXebkWlj1KmhM1v/lGapq/WcyC2KsKQxYV4bdK05+PJ9qy1Zxwn7t/uE7ii7B7oiYMs6xdznrTt9ptO3TpQry04if+V2p1mTxCeq+7AR9LJ6IEbm345wPFmLVtnhOvEaXXpu42CsB3kWeLF8SVsRFZx90Q8nCn9I0mcJzfbfvSYy9bFbac7WR4SARQxCezLgGWhEjraIeucgFmolbOc9ebbii6Y9nPGYyuaoYcGFYbcPJzWX/jm9UEn1rf0Qs2DWWMGa+AXfC9owMvv3Xd74OUtRb09uZi/oAksWVwAqg4obLojmpzfQf908GLg8Z8ACMb1aqR+F4qjliG3eqJoHamrjNWQ9BRvQGh7ggOVD73YbkBwD4+eZ1LvcVr92/zjDJ90zPm+Dptw/8gh2w7BBEfzO1ABcpSmEzZdO7nfgRpbIUUPmZW9AtIeaaFdy4MLQxjzYIhJI5XFuT+RxUU//BCYR4Sy2Tj3A1MD+j4baG88Jo5EvN3+GqyJ/j4mqY/QU2oz2yOLAbx6k991wpD1YBcklgA4ocyr5TGxpXIBjvr48deDNX85UFBVmGuwkK9njlEYBpGnOKVqxysk/vsguY7740rtS6ilCY0PTOmOqbf9ySNnUhyXk+4RNZADLi9+mqZ+qr0rFsWiTuS2zFzPGUfhqfZEhHz2b3N7cmjP09dC79HtDM8oKaZUAQ9deJrxNKLTNqymON7G1Uzy3J8C2iYpHvwTAHeHsyNJ/w/D9/ssw+RZxM7dFHlmL7oxaMTSXG4by94t1aAuDgYpWILNj37lyF14BT4gWNMHJzNN25iXrqwAy1LWZ1FTFWp8E+pkIK/AA07y0lyCfniYGsc9OgvdCIti7Q9Qo6o1ORDgJUV+R2IOCDy3yRfpQ/gfizmEvn+D4kIGpUKiTlEGOaB","layer_level":4},{"id":"5693cd4e-7ec5-4841-92d3-413cbcf7d614","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"非空/空值检查","description":"null-checks","prompt":"开发非空/空值检查规则的详细文档。解释ColumnNotNull和ColumnNull规则的业务场景和实现原理,分析其SQL生成逻辑和执行流程。详细说明配置参数、返回结果格式和错误处理机制。提供在不同数据库(MySQL、PostgreSQL等)中的使用示例和性能优化建议。包含与其他规则组合使用的最佳实践和常见问题解决方案。","parent_id":"8195f94f-7c42-40f0-8e98-ab1163cac8ae","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNull.java","gmt_create":"2025-12-25T23:47:36+08:00","gmt_modified":"2025-12-26T02:34:24+08:00","raw_data":"WikiEncrypted:tD4o3g71kgwbR4mYuX7udbNz+WFotcqGDtbU8WLe4g1EXwMKxt9r2QoYuBTprhmKBaVwj1mQqSi4bSNCmRcuyH06SiVA6UqMqWT18BfbRRLVgcnqhSsF5hOnSAALCJALJVLNYAflB7cWKOsynB2GeYkrXafRr92dLSisCJ5dxorGUv0D0J4BaMkDkIThMfRFrKjrpaCJU6AnHcORrLAghzAnMc+jDq7gvznzOypK05ZspdGzKHiL9LYuBChay98TinAX+Wvar07+UUytFb7POhAhUm2Qh1R/0UMihAaYeXD6FfUKuH/1eMftsCCUJMbRxdcO/CgcTKxNXq69HczoBVGllUCx1A44+AHa8mFgbHNxGi1bQ80ar0uyZTctHUt1D/W3xGO7vRsiHGf9CKnsXDztsJzSvzJtFvLQ1tUcFSNWVFJ9qeZpqiS4wJn/PwLlbjIXQTuE2Th5kb4Yj3Ahq3tyWqjF79ZWtohzIjwjcJC73oBKwbEiz4CzYgGM8iTULOB1z8tW8qzxc61iCC/z3Ph2XYFPiT+j6cr4JrNLYQjd991Iqa+BBuH/HmV6QNwesQlvYTBmSVq7uPiwfJ3X81OOms6LJ4hEjI0HnLDtqqCzT29wyePrudK6Kjg+gU5TWpebvFU253HpnUH1d+zohl0m5nzsqztRvCiFhodOCfaGCNLoS8hl1AG7XtpoGUWtE3oqOKuvmBSUCYCXUqWZTVqUK7UlaAc4ZUtXE0p1xI0DksiI7SWOzVwnUCpHqfdto5RFRgATNAGPxNVs3n8ySSQTfWc99e32LvsYb49DUbT6RCclaec2ivSVyKyyXoZtnegeYLSV1HKWkIwqP0kszFHqF7Hxq6X6TuLJGl2gj40lhYGiC0JVwPIFvy52En9a82xSEqEOXu1pIIRD9UN0qF+I0bqSBiaRnCcscJ7ZXzqNWuetiNirrLIi8Ox/LVzAW/XfDkRYZb4/3VNBM+DwwlqIuGXY9eSBpMGs5CZBl9Y+4SoSpI9NnWDUxU9AMI0iq0IORX3htVmlRVO9Ri4wSzbI8vbnHxFYoUAsXUQH/kKCvRMK8/LcfIOWFlFGjWPQj3Wvx9/T2HMPFhILvzoAlQ==","layer_level":4},{"id":"6e843862-8b0b-4c13-af7f-449ef45aadd7","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"日平均值策略","description":"daily-avg-strategy","prompt":"创建日平均值预期值策略的详细文档。深入分析DailyAvg和SparkDailyAvg类的实现逻辑,解释其如何计算指定日期的数据平均值。详细说明该策略的时间窗口定义、数据聚合方法和Spark执行计划。提供配置示例和在数据质量监控中的典型应用场景,如每日订单量监控。讨论数据延迟对日平均值计算的影响及应对策略。","parent_id":"489baeb5-14c4-4d03-b73b-be142d956487","progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/SparkDailyAvg.java","gmt_create":"2025-12-25T23:47:37+08:00","gmt_modified":"2025-12-26T02:34:58+08:00","raw_data":"WikiEncrypted:Dmn2WSDytSyXriNXg+5YfeBC6oQqB1cy2e+B02XCnKL8abMkJXCirVwMdKWuXwFUshAbPY0mCDrxxQAUhX3UIAFnPCxfUznvP1SuO1xUve9BIntDIIz7tPWZL2G78hNwTM6yV/SDixkLoHrPWckV9MwGuS+nTMniOYM2UylZfWssKFe4fGnPutCwYPeZ2dOrDuFU+8N4SEGehSqtjyks0B2bU5XkJHJEJLXhM4LHd8BW/p8g8jsofaafO1kz3MEMAOvnG5fWMx8IoGH++YCUXCuTcYLcnn4YeSAWnn3StHRiiMJp6cuk0umVJnTKcTrraJXNR0T13VCU5/xhhCQu/wkMaYLrCOiiCszOdKuWmjHN/qrQ/1dZpFscaBd108RtalTFj5OlrLZJCTDB02Ii2voaPdQ+GF5Ebe1CedAsmP3+8J28cYo2m+iqZk1AL31jY0xyUuLXrR1Fa4uTxdDO4DbJvtrMBbwbW5Y2dFMrQHj81Kn5aQQG5FVcrt0a4CbsF50RbEvkAAQw6y0tYLZp32eI9j3+mHL0bVFSd0PC7dBKi0+67VOAvoa/j1F/kEUSFZ2VY/Md0bNEVIaF0a3uLA+ImpEY4UT000z5WdXU0f2ieFb+8DopVh8G3qaoLDfYcU9O9eaV6ChOoQ6AwKhZJzuPMOXFW1marhLC3XlMfqbws8wzDdDmj+NubaO+GePZueimWy1TQFiyd8zqhc63f13YE2j+TeY4iiLX41/sOBQQ36X6Vj5vUTzbI5+XJwHSu0VT4S+/yVBjPEu8FJPjCrC7BOaOw6lD0bOP2b9xQAZ4CVPpjEuRtKjQX8Kw7w4qRrysXCEdcFLgkQy9PnV8O9f5k4dEmwarpcM/yUkqyKu1e+fMiGlBZGOaDkd9gWnV+AvK4lkCyFyEPA03925ia/JWp9MXBUpm2+CQwWS94yHuFva55dHNPBSxl5Et1Cq4zYcGMncAVSlKHQtPN7JnaUTpKy6ELx1t2vBtFtl8F3C0gyDHjo0FMADEhPjy2HW2MewN3NCuBtKPWajtQmKfIJoLwzvFB7R5+tnADe+bAYZ75jTVJbceY9RRdOUPu8OKyedpvnknmxixY6PbAxqhLIfcsZMJplCMK+xOcBzA/jT7JYrxo5bYeNMFtYZ2LcC8NmFZh4B/IubQUBYghUeNbA==","layer_level":4},{"id":"19ff2e79-166d-4a1f-96e3-229b9d78a6af","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"快速入门","description":"getting-started","prompt":"开发详细的快速入门指南,指导用户如何在本地环境部署和运行DataVines。提供从零开始的完整安装步骤,包括环境准备、数据库初始化、服务启动等。包含具体的命令行操作示例和预期输出。提供最小化配置示例,帮助用户快速验证安装是否成功。编写一个端到端的示例,演示如何配置数据源、创建质量检查任务并查看结果。针对不同操作系统提供相应的注意事项。包含常见问题排查指南,如端口冲突、数据库连接失败等。确保内容对新手友好,同时提供足够的细节保证可操作性。","order":1,"progress_status":"completed","dependent_files":"README.md,datavines-server/src/main/resources/application.yaml,scripts/sql/datavines-mysql.sql,bin/datavines-daemon.sh,bin/datavines-submit.sh","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-26T00:11:54+08:00","raw_data":"WikiEncrypted:qfgbutC7oyxR6nMxrwk1ODnNMBEQ3/sG78fQT1yXWjuiNN7p/9UiziFtG8VxSN3lDZPQFx0/QJ3DnzLYLtDRB61nuJllFcx9iQ+ts3Vd4jh4qB9Wu6jytn96PPzhGZ1zmOtayjrcwG0mreLJRXfp96WdWDUPHXNYV+PFka5xSaJ6tiYHJQtRjh/z5W8hbCF02oYrr57ytym7qsR5Rxi0q+Da2AOG0B7q8FZVHn7S7PoPvWajt2tzdNCMcrEMUHUBAGQtZCLByX2s4pSSbrFOWLlx2yvGCizd9zRhL0JqWrFGmMWIHGD3TGiackQpkkmh6yrEg9ofMReCqaUt8pVR1Jp1op2yWy12uQEmVv3xMisIYGRugic8ECXEd/zm1CWuEboT/nDOvQqlst7lN3Z1ytY0f10kZHmrhPQo5pb4MrhpCSiBkYMtCilJ6ZoBFt2mZgEuxq430IJ/oK9INHuzggyX+TzT2DFMWehgid5/glRvRYh/KO/Fo4+96kTtjJoLCS/qAz0PwXmaMPevf7X1wz8a5iFsHPcDxdRXxawMzsBMjmmUtJHZb4dc8GgntwEFR8lEA8Hq2wPjnk8tQrwUirV2EipOJYxxz1Jksl/O5UZNUiFGcNDwV0fn4/mJ9sIFmyF82yC1CgKgtxayn1h5R66PYVdaTTsOR7zJ8JOYDG323KtvQ708CTfzvjnvp9pM/9Hux/9130lyIBvjzPzi+5K7YJJa5J1e+yfeBOmHyonGaD5e2CHLqJ19OwvFaS0mnIv/Q2/1TPvS6VNGuuBcylfqRLz0eUF6RtEQjrB/4AfCYJrt6K0M/C+sYpWoZNkLF8wPNaeB6o2JrNEewry0cg+bI8BHIjGpDot87La7ehzWBD8Y2C1I5i1RlFLiunbR8xdHZW4l8zRoFDbqQGU3THntllEoEwwZDix94u7eTLr07hONL6pcCCCmxjGQ+aqM+jMXoj39qZVY6OdQg0ZxyqXLp1M8QymEDZ6W/sNvFUOgSSK4XDCovizfmKx2jsk4vTz31u6G4ddE71oRFH68Qa4fPH9yFulDNK03EiU5sIQoEKyrZCXGwMP7t2looPEGZltkT0G9lmZ+x4hXDjdUF3eS5ImD3qWnzq6FedzhmKDmP5JupcuEO/y/cL8kNh3P9hk5FT8217hgzWeqWPYqPctKxX4k1kqqc2aRsC+yTWLoc7rrR87nSrGOpff2OwTE9naFN3M/2tm1Rr60zIZcrxgb7t6nDZ2VIJHGH/3IMHnsXxoAbJfXuRwAdwYwhHgKEzNMBTB1Zf0bCg3j/woHRfne3CJBWp6lcxpYhXH1AmyPNQ9dUzaDqa2guGxHuEtC"},{"id":"a19e7b20-774f-4c69-a930-24d3fbcd2f0a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据质量","description":"data-quality","prompt":"开发数据质量功能文档,全面介绍DataVines的数据质量检查能力。详细描述27种内置检查规则,包括单表列检查(非空、唯一、值范围等)、自定义SQL检查、跨表准确性检查和两表值比较检查。解释质量检查的执行流程:从任务创建、参数构建、执行调度到结果验证的完整生命周期。说明质量规则的配置方式,包括阈值设置、预期值计算(固定值、历史平均值等)和结果公式(百分比、差异值等)。提供各种检查规则的使用示例和最佳实践。解释质量检查结果的存储、展示和告警机制。涵盖质量检查的调度策略和执行平台(Spark、Flink、Local等)选择。解决常见问题,如检查性能优化、复杂规则配置等。","parent_id":"68f6e22d-b8a3-4a52-90f3-e23d8a3f0f4a","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnDuplicate.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java","gmt_create":"2025-12-25T23:41:06+08:00","gmt_modified":"2025-12-26T00:15:10+08:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"4e0ed203-0047-4f0e-b2d9-d7fa1cf34621","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据流设计","description":"data-flow","prompt":"开发DataVines数据流设计文档,详细描述从用户请求到结果返回的完整数据流。解释任务参数构建、调度、执行和结果验证的全过程。绘制数据流图,展示请求在Server、Engine、Connector之间的传递路径。分析JobExecutionParameter的构建过程和序列化机制。描述执行器如何将任务参数转换为具体的数据源操作。说明结果验证和错误处理机制。提供性能瓶颈分析和优化建议。","parent_id":"401be447-6b3e-436c-8d7e-a0845a921e20","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractEngineExecutor.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java,datavines-runner/src/main/java/io/datavines/runner/JobRunner.java","gmt_create":"2025-12-25T23:41:09+08:00","gmt_modified":"2025-12-26T00:14:37+08:00","raw_data":"WikiEncrypted:PGdHQOrMWxh6s6galmzx6/AH6koaRsRZ2mPCIcD6cZMtJrKupqkAZGnHMu3UD2SsxK2caDRE6y4vC/eYn8KLZBbBzs5N7u7j+tHRZKxw5DYLO9EnBWXlGOiq4m9G1DXUWnyGEhzwEU+/spbevW5gCU4xBqkqRU9qrJu2SWVxAg3B2nezW5v1BL6dVPsBdGgZBAx5FkOb7wsw/cQ4g0q3NjgA2O30/HFYAado0LjRgDp09qsQ74e6ZiytYYM9ooC5uEFrKT6B8TDbhy3zbyl096CubVKZx55YEar/R0FcvIeiYNOV7gz6gXz98bqJ0+IeX1T/UuU/iPfN/aGMFvpNc2tY87ZEtdOoGWoxveLMxMCkSOqi48ZY2L/PAkRCL/0JjV8h6UNkkfD7fZJjvZewacfGiqUq4jydBb9dJ87O14IWFzmOu2IyAi+st0CdD1DJX/mXfTLty4EsmjlFyrJ0IL08YxbS4UyrT7fxdEJyscqZwA/rL5JErnGkjqaygI6mLuelyEOAvS6kAF6zfx/jTV3Qp5YNxu5wDObOiOP1pCbG3wMkxTNUJftlWi6rfPY5ikclt0Ue4ud7XZJZjZ7J5K9YPrabPr06EraPjFA3/1sCFvHNeaakTSb/wQTPbintgjbPCKdjqenZ9DRiJFn65DtEtWfw5CYMDJfk9iVoRUNpjl2aqQfj90GDgMxKVQJyvOeognGBWg3Vo9IDN17GEgtyuxvk9590PbDcAr4C5s2NWsTwFnBb7QgJlFMOP6+6cxTaioGHHaIRW+58CZ2xUhY5RueYJFBNAwz2KAKq5MhK6Htd6RgzkpkHa2or9aeRFnITgwXUXkYPFLai6skEwmJ4FOEIO0uOOe8g6EQ4qGLGxyQq4GRXod9bPSy8lFqrw2oo1u9Z3vdI4OlNhF/i//6Sa8lMmNDj/kwJPHDU2iAmOh7LzbbyooVVJsqUmJtbqA1OHVvxWq1j+HS0lkYiXRhNx9adHjKB+ox/no95YSPnNJhOi4Y0HcZXInDCO0YVXDB1jXQJIlHP5pq1H3/mzXkroLfCtMyK+e+ZX5Iszo6ZgG/AYI/85fwxgKruADyWtbmtsyVNHMhaqJYTg+OHZLG7c4Z3A3WAZQ+6WEym+CC/4nZGUavX4Nixii0kidZt+200XZz1Ff/vpuodaO2a+LmU9MV8k3VdPrZIq8/DEU3I+RbHmlVKBlgDjUJZkO9Q9qnfpabf9QoGWtjrgVVUUrKDIQUlhQ33Tv8f8BTe8ksfM4tpw+IhzlNA2u4DN8AQ6o1ord9C/8899OmEuqg0JE1M05fmAIJuhF6N9JaQKZvTeRiRp7dFEmXhWn1wW6GgttbyCO3Q8m//FgvYNdoz7HaROAck/Fbt/i+QzPm80TZW4a3feMYsrTT2YEPau80vYrEpeh4GVX4q40hosogYt8A4Xz5jZAMVBJjPmm6/MCEln+fTWW3Zx/2zOCP6gDKBHjIvYRDLe529nsDAJGbVnNLgxegiwuuWFlOGkIehKWI=","layer_level":1},{"id":"bdbc7ff1-6561-4953-bfe0-96e43c8b3e3b","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"datavines-engine模块","description":"engine-module","prompt":"开发datavines-engine模块的详细文档。阐述该模块作为执行引擎的核心作用,包括任务执行、资源配置、引擎抽象和作业配置构建等功能。详细解释Flink、Spark和本地执行模式的实现机制。描述引擎与服务器模块的通信协议和数据交换格式。分析作业配置的构建过程和执行参数的传递方式。提供不同执行引擎的配置示例和性能对比。包含故障排查指南和扩展新执行引擎的开发指导。","parent_id":"c391a73d-20a9-4e3e-b13d-54fba38ef59d","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java,datavines-engine/datavines-engine-core/src/main/java/io/datavines/engine/core/BaseDataVinesBootstrap.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractEngineExecutor.java,datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java","gmt_create":"2025-12-25T23:41:22+08:00","gmt_modified":"2025-12-26T00:15:59+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJ8ySUwFlh+y9gwRzrzB4lcIl/Ue2JPPFSsbgx1pjQB7haOuxoHcQIYa634bVgD7MQQ6+DZBvffVU2fx9Y7SKuk1xJ9XrBNVVpzSzEbK21zcCP2JgEvT7dznrZp6oh56WGGUuacWcUcy2L+vSJJSip6XRS70acsSQiDwwatn3JEloiWT5WPccI8Z2igkQ9NuOPC3Z+5iBx0qFY8Ute7LrgVX7ovsaQ+rQja5gdKQPc21SHYNTu2XCHGdkNV0QaghoJcxCVv6oNlOYgFq+kA2hSUi7oNFUp01NJI5U6XjkEO4sjkzuW6EJlSZnQt13153mEf+NyiYp7Jssr0QUZlgd4dZSrllE8nsqASNOCHbFOCc694S688wTmcRrDd3YB7vqCa8HB8F3zc6xAWjfatFBwOM0lL0caDx16ts6Htf/cRURx11g9ntX3AdWyqTimYVblcKroTeRfRybnds93WqEfGaqkDCk30SFkqmgFhoA8QeUEk3Tc4ueKRSHn1NI6DqoBTqFzCtr25VoURYI4/vDL+J80wfvZPQCjuleCAgrv7tozB9EvJo2QKX0CC8upBC5b1DiUrx8t2yxLk0Nrcfkv64Lhn/v6bukPmtPUB+iK9IwCxFig5vQQGZ3zOzQvqHQVVadPWSw/CMNxZ79C4YmjUY0aKIo1oxFcqmZo6egdEuWZwNESSdMEKiZTOUaeOQs3VZwCWkiXIWvnlvroMap5tWudZZ2bB5cAVN4VuOuI2oKLYKbR0/R7pmJVSkJkNdzvPrTrDIkDiG2XKPHEdZcixTy8CPlS8MAquDcwkNZA1nJUERK+HHy3afqALCo+rVBHKBeyx0R1Mnue9ZrSd3pcO3Wq0SwvO9/RYSbklwc/+jEIBq3Ht3XO46k+vEu04YN5K36nG7LybcKtIbfbINn4Mfh7aooWBZwV7dXJtptqWWwh7crc4kD7nWqhMiMlqZ9W2bnYK4wrCSxVTQKjSJgyVqMzLGHBJ53Y5KAvUp+jqMU0lVGam9HHqlBky1GVeLJ96YcNo/AvhCB6Il3xRsTxIQFTM+oognXSQf2ugKtb4aLUzvLC9sdIUJBy0pbntHL5X4oeXpnQytcyc/+EEwuvYqYPIrNpQ99RT3oyq3/tkCh1IbOWa+wBLUJHtlUum7zrZMHppA6cG9Ygqt4gQabCOtVUUsc8zMcEX5yxWp1umCAANEJy3OIj77VnrvXOaISK4rAE5EcM/Qp3OqrqnAPQUI/vifPcH0K+aFvGZp5XGtBykS8/xkyctFI6Y1uMqMMfWWNg21W+DDOHg5G3CF2CLphnt54iq1UihKqOc7064Dc1VSgtXSWwYx7g1Uih9/oPAU7/WNNTUb9zITU7+26HhoE+xwrnKMOwxe7UM91yOY8/HguBK7kvBK4hd8CqzYt7h5Qgl8GwLXYt4SivSEfilO22A6rVYBcEMFouTsxjYWEMRVPx37J3bFPC1kqnvT1pWdmVv/alAUoU3AvknA7oQRQ/Ptm3mjRmJM/B3J6xLXUnuB1lABVdes1kUeSSZ6bzqu66vK+N9ZEW+iYOAlchgc=","layer_level":1},{"id":"a852cf8a-c040-4da2-8fba-59374cd92ac3","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"检查规则插件开发","description":"metric-plugin","prompt":"开发检查规则插件开发指南,详细介绍如何为DataVines开发新的数据质量检查规则插件。解释SqlMetric接口的设计原理和实现方法,展示如何定义指标的SQL查询逻辑。涵盖单表列检查、跨表准确性检查和自定义聚合SQL检查的实现模式。提供非空检查和行数检查插件的代码示例。指导开发者如何实现预期值计算逻辑,包括固定值、历史平均值等策略。包含测试验证规则准确性和性能优化的建议。","parent_id":"f7482163-91b0-43ed-b702-cebf50029b91","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java,datavines-metric/datavines-metric-plugins/datavines-metric-column-not-null/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java,datavines-metric/datavines-metric-plugins/datavines-metric-table-row-count/src/main/java/io/datavines/metric/plugin/TableRowCount.java,datavines-metric/datavines-metric-expected-plugins/datavines-metric-expected-fix/src/main/java/io/datavines/metric/expected/plugin/FixValue.java","gmt_create":"2025-12-25T23:41:31+08:00","gmt_modified":"2025-12-26T00:16:22+08:00","raw_data":"WikiEncrypted:wqMZoWM7JzuUrLNEmTF3PFKWejFHxWXoI88DJt0U3HkihaF5WZTb9LT2XfHDJtkU+XdvgfxOp9exZB0nqW9wzN/zH0uexOwiafKErQUhaLvCSMK320T37lNcdbpT4K/e+s5sYjhVCSw4esOMVjsRqn0j0BzhTxNd0oizhOP3aGYnKHWS9jtjhK8/OQ2k05GXVchfNoA50/chC0SIBSPfR1OT1Van4hEuk5oeOYXJq/POvXWxPtRHK4S7qkAGjoxZj8ID2pjHbBOPiHSaVLZIlkPS5ymSqxAW6n7PFekUZxjQmsj6bk53dAo4jlhMyNRHdE2MCddKOo+tWVYDWxaYWUPPKahEJwOZP2l6tj00nBDc67bkuqMlJe+yAYFffRtPXejpMiZsCXIy6iC0M0M0WDwzB9tcoKbRwuwiCzWqahN0NO+mHS8yEYWNBTFtoRd1GUH9Syy83L33/AUo0tLdzanUGI9+q83Mgyi65g7i8O0PJUEcoYKz+xvdIxzMLTH6r9EGU9JljHTusnS/DOZkbeWOCBKyKiuUZpPf19cAkXk0RwXyayh6sYiWumD4foknG/jV9vIM+A7vY7yDcZmRDEUCb5xlsHKreQbEF2BwPjsejoQOuMX3R+OCZDT24R1ZfNjKEnD2IHccA3s3ot674vlZ3QM4nQpf6/Am+E2S3wbcfV8/D9nykL5n427oA79tsqMhtoDzBHqGxxZt+6G6bDit6z6TgqWLd3XCmmG9euZoZs1AA9hvwSWvEhmizea2w6XjNIgBRfbp4pZGcPh+Uu0n3ntexJijLId0P9mQ7XqL/SwUJ5y6XpVDVuybUyYZZaAJDvN31uqnQfiZ3evTswi9UI+scYW/Gb8n49O7fwIzkT9BmGpta6xC3ppUwfpmTNcrzcpLS3si0YYpbxK8ID9cqz75OcuX0pqNV1s3qBmZWCcQoHBhcXi4aDBpuS69p00XfhVZh0XIhTNX6+ywKhp34p0e0u2rRO96/YDFXnJzXFGjRS37BOH8zAoO24jUg/yzoRAaJZkqIns/f8H5PtaRLRpudML1wAuMxKnK4WoeG4pBJdzuyewdmfL6wFJgLRcswDcDDUS6RzMohnTTTrCmnn0MxqRCASLP0vs9vtNBwoOKKVfMk/kZ5/34+zyS9+gjNiSDY417fwbAM0lHcLsObjo1JXZbENmHUCIwpndMsgHy6K9XM4X87yw5qrsjTdc+8v7FFlYJhVeiPxpO90vT4zwZxP0Rjs3ob4Xd7xj/cRtgRfTwswmMUcc5KCoJYh05xtr0Asv0mZ6lV5tbmu4XruQzYph8AlFYIoAozNaqk7TA2ZzzzfbwriU+95ZiXenHFBuvomPnQBcyxV2ENhS98KBuxb3IIto68wlB0yVI2XFqP5MqmJ8GdJguMP7AyeVIQtvPntWbnHcABj/hzkg2w0cKh7LO/UWJsV/8g+0CF9OrgqcZmwBP7LU/PB8pAHX1nlLm0L3rtxbwT3d3J1C7x2hfarfdMdt3tGk756j+ZDN3HKmEH8AR5AanhA9lAwmuwWr6vAvtmRiZmcX1m4GonItlAXu20voWUoH3eGSuT0ScQgeOd6lP/hYzwbVY83iJYdb4Hg6uTx/pPWHPO1GhV+U7PrfQQyS+x46SQ4qOeTzazB+hm2XfS1WoZiXqn9p9elaKg2zKO9xUkUWiLj+0l4jBMHqrtyHdAQ5S4Nxs6xxwclee8CI5Z3if9efSPZrVCTbNh3BQfyY/IGtb3TWb8GdSpexp9vEKCJWVZ8aMwKJLXrZKInOzVBGKqANJbzr5Ffr3iiP6nZ6vzRKjiTQPNx3EyBENkbFNO+pp7GI=","layer_level":1},{"id":"13e13644-8e2f-4f5f-aa08-89d3878d5113","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务API","description":"job-api","prompt":"创建任务API的详细文档,全面记录与质量检查任务管理相关的所有RESTful接口。详细描述创建、更新、删除、启动和查询质量检查任务的API端点,包括HTTP方法、URL路径、请求参数和请求体结构。文档化任务配置的完整JSON结构,包括数据源选择、检查规则配置、预期值设置、通知策略等。提供不同类型任务(单表检查、跨表检查等)的配置示例。解释任务克隆、批量操作等高级功能的API使用方法。包含任务状态转换的详细说明和相应的API调用方式。","parent_id":"b4082be3-2f3e-42dd-89fa-9295da3c62a6","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-server/src/main/java/io/datavines/server/api/dto/job/JobCreate.java,datavines-server/src/main/java/io/datavines/server/api/dto/job/JobUpdate.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobVO.java","gmt_create":"2025-12-25T23:41:32+08:00","gmt_modified":"2025-12-26T00:17:14+08:00","raw_data":"WikiEncrypted:kNxyuEv6QFzNyCfYOgB4avAvj+DSzjBxhjAvoDaV3TsjpkAaByMolIGetQFIYT1lmkStQm3FEwNRFpYr57O1Mguj+LvAwdGGK/UQcyR7ek2DvFlIssiUfd9h2l6GB/1ObbaWyLrmES5tafv63Zlqlyi6ay1zHSSIYf3+XHd3TiBrZ5LRcRX2mToBXIr0CQ9RfcA2deDZ9QyaicXiwOsxiwRnawrIv9iIlN8Sw2zjGm0zvCSYkpN62g6WlvAU6OAL4PEefNuFLAzfLMB7DKWqYs4Pffc8a3hrbF7VWON1NlazgotsouK73AGwMhxdQ7H0zwr4We7z+WmbZLB/RuOcdq03md4jFByBWzHRhb07E0GkpMjxXBd7Ri7qcRAoy0sciAnESm2UIQO7D8bhSE1ekjePPKnONqmXndAXk/+Wdql6U7wNr/+gSdM+48WbhATww3nL6TeN/6FpAnjUs0zKIL8EaYeiKZUXTKxZgOrztwjgTBJ46pbO/aL6EKbp/5I6qymHZzWCioTW+SEmk5W7l5xLhfA05wX7cCipvHtAvkVpAizRzETbiexbZeEfiDVG3EIB9HFWBC0viw72/gW/+sH5lDpHycXaYfFVvW89v9bVSUNzF6mZsJy65d/y6FBS0bvvW/W0j7Bx7nkj7AHn7DRrGysL0YkHGJ8gSgujjpVfqO14Wm7DcRzgvVjxVDf7ZGz/tQG/HnsTN4PlWqSr0o0bSfc8s/tghXbAsRHQod2MOOU9p8xWa9G5AZXl6WKlz/PvPRg95r9hrZ3ijdMVHtJ/TVtSC0/mHm6l7Bmhd3JCe9BwJp/m3HPD4bvP1vWmOgdk7qcd7gtCq2VE4Z6nYhrVUmXiyoCaKg+6UwDkXI/IH6A/O5x25sj5HjwzaWs8WAZy5zeTjAbA/7qGigR+7lYgzOM1cI5+wkWT15AA2hXcmjzyLETnxjs93ANbtYMRMQPFDu15ztocuOJlmhNyArmVRAGMt+xbbhG/AvjBmfH/OK3IR8YCz1bEZKECAnx/r0MvMNTWxlMylVoYKiawwJZpDqP3E0/shMdZmZmBCLdpBGPSPn6OEpbr1egYV+DZGBicQDkZeZE6poZRYvZAVDjr89x1dFASVE8n+c+6haeWsIcwNZW/7eRcEjOM2HReCjPbQGl1LHYz2LJfIIoLGAw0DrpYSyDzIPFz4hGvFBWpe/AAlahCmfL8eaV0Y09tnODr+JczkxyfYV50yrOigaCWqNv8wFW1NkHi24IkgRvKhprF3LYN1hDure70pJzjg6BQhPJBrR4rA1aEWdIHdVw/NMpqdhcbmU8Qb5ACrw8SNN5YwoDXAjfEkDUUiAsIfCIf7Bq4BfeC3bPLtMfn2gQXeZh1BnaaHbefNyUbwy/dS2f/Clut7AxNOUAVsX03eWMIGwZaV0CJ8f+R6hylxyDXt3tEx1Gat/TtZ0Kd5NWAor18qTZwPISzBvKrVZ9p53PFx4VSDNRPev9KT2ot5w2tEKZ0Z50PJjlBVOIdLiSAAJ+Yaa/WQ8N3vL+08f7DD8bkuaXixJOjvk9cdrR6rf6SzJvJqxvvS8qi2AXsOkJ51ZsN+rGLCEQzTPh686gApeLQdDHArq81/AooVyAQlw==","layer_level":1},{"id":"9894253d-03a2-4203-b66b-195226043287","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Docker部署","description":"docker-deployment","prompt":"开发Docker部署指南,详细介绍如何使用Dockerfile构建DataVines镜像并运行容器。详细解析Dockerfile中的每一层指令,包括基础镜像选择、依赖安装、文件复制、端口暴露和启动命令。说明如何通过环境变量覆盖application.yaml中的配置,如数据库连接、服务端口等。提供构建镜像的完整命令和运行容器的最佳实践,包括数据卷挂载、网络配置和资源限制。包含镜像优化建议和安全配置指导。","parent_id":"a5e4da90-df85-444b-85e1-80088657b90e","order":1,"progress_status":"completed","dependent_files":"deploy/docker/Dockerfile,datavines-server/src/main/resources/application.yaml,datavines-dist/src/main/assembly/datavines-bin.xml","gmt_create":"2025-12-25T23:41:37+08:00","gmt_modified":"2025-12-26T00:17:04+08:00","raw_data":"WikiEncrypted:h7ADvj4WLJHyulzCl+z7kMT6DzaQnlgZj+Vph23KSPwCAKwAGu81Jfoj4zRMdPAHZYLKWoFF1+HyfE0doyfQ1UFi++XxR/2hHM54Ofw0L7aDw1GfRjO4ZlRAMtT4FhJ3AsPQBVaEq9bY9zhpB+yPHZgSjgT81b23t0KvTMrwW5bbCjiXG/thkcsHBWIz4+YMLwAQzRd6djfzkpv6pq3sd1kPhnwgwJFZOFxy7ycYhFc8RiPuXCGl5pWXGwxFsdOczFAIQIUKbjdLa8JHFqs6rTnt9z7HxUw5H7N1Q2RBDv0vEGCyV7zjytlUitFC0jY6OKV2CYZuoTkgIB/6OZdngP4pYBweUFf5GLW2eunVa7aU/GR6AhSvi83BLUSff1l0oqRZJZ0isk0gfIBTbYbNK+OYvL6pt9fYr8kpqs3Av5MTeksJ1k1hoTWCYvCIoAisUf1RDumBdqoCAY48EJksr1tntPQlO2rn/7TrRvIhmuAV3RGq1uJXtJPV8Ex7HFg81EgjNAuyTxGn+s6Mk8gIQzv0W0VmbNU7GXkHW3KqpRO6da8BZqx34ggmZinR0B2UPrXFsH7oAJktCzYdQ2JS44yU4QFnicypHY10I4gUA1hZgyVdqBWJek6yVoshO+KR/W2+A8ZdiYKzcJlKBP4kL6qGXi1qGw/dGNQLKl3XBXDF/8uJE+UFsbLMTOzofSggU0rT1EW3XZ0Y9cthnaeptarTZfAVxjKPxOEaUSl2t8YD2To3iPPwRAIu5z2lkq4Tg9fuHgnF7WtGNNW4L0CdXhU9O4ELnbmMtiKYIzj2vanExZ/FyVKAKrpmELLTybIJKFVUyhBXFr0O600WvsorSknvuxKPazfc96MvvkO7tc82e1dhyjo+/k20QRBrBcaed+lc3+J6qn1k+rdEbX4GZBkFSYw68wGPtQbtweAcOIzQdkE2k0DbmPj4jH5BbxfO7HhqxDl/3Md2aLoNS/aPjkkrWjUxkl8QIARhhcxk6UuYxnEu/61QqOgGdJC2uNpxtkGgWOmwKCvVeK7JLV5ilzz299iVUb41ZpYfBGG174VuTiy8q0+WW18mX5g8L083LSC2pSgUECLYb9Ch+Rnk6HoVcANFsR4B0wZoq1Gme2F4GXMrSU7WCjVI/cTBwscjSqQ1ojVTwhOew0q3lB3gTw==","layer_level":1},{"id":"3c7fa525-a12b-4451-8146-b1bcfafe2f1e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"表结构说明","description":"table-structures","prompt":"详细文档化DataVines数据库中每个核心表的结构。为每个表提供完整的字段列表,包括字段名、数据类型、是否可空、默认值、字段说明和业务含义。特别关注关键表如data_source、job、job_execution、user、workspace的设计。解释每个字段的设计考虑,如为什么使用特定的数据类型或长度限制。文档化表的注释和分类,说明表在系统中的角色。提供从SQL脚本和Java实体类中提取的完整表结构信息,确保与实际代码库保持一致。","parent_id":"1a586877-260a-4728-a2fa-ba930f91fad6","order":1,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java,datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java,datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java,datavines-server/src/main/java/io/datavines/server/repository/entity/User.java,datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java","gmt_create":"2025-12-25T23:41:51+08:00","gmt_modified":"2025-12-26T00:19:40+08:00","raw_data":"WikiEncrypted:TWtD9cYU/QQHU+vD+ojNNhzo0YoQgW7Hy2fauPOSWED9QxifsQpasI7wxA0bvwYbCgKEw0l9HjvM0T2CzITW5hjLqwUWcldUfx1VwsVTNdU0YQ4eVHn6qwwyXrC8vPM+5ENzehGZ/4SOyWWn5VXUwiAgcD+ak+9A/l1O0itQKS4PtQtEowlv63q8XI4T3hSpb+/e6ySw6EdrfmlCjsTSahqOz9BTCIsqisavHmIueyF5lGt3b1RvJMITHoYqP4qHiTjGxYfCRj3PsX6/7gEeLMSzx8ehtcuWq4ogJYeAN30exvXMH5MHGiQ15NsVHYVeFIUsy4NievfW1MnOsxl4gjJZ6/HRBomS+fHSMyKRZeAIHhpaMXX+zDaM/7wuUFhBDuuReorDO9p1cpbPMDXJ8odS2Z6GexRQmvyXbZv+AbI70SNQyqKiJsKOnJwfR9G7aBHVrdLy+tUoJYAYWk3G5yAoqdwFvMKl80Eoa8yChly5u8s+c5IhV6jaUPU4oWOxjyBhIttB/qygRXOlg5nz7af8JlB/ft5cvEctqPSCeH+Sv/psft3ANhBVpTqBr94LY95exVNV25I4ah2HdImPKl7mA3eshqpiVDwLnGvZUVO3fLLstkM1r6sZoI45MnYP26yaLLL6JTAtIdB1GB3r20pGKpdcJxvvBtqMlrh78HG57N3+3+MCb3S+dDPlzRXyD4fPAPCnAmEx3e0UObJWoE+4R4oCmOOltxcYFE5HPV0qEVdLY+Ing8wsdigUZV7GqzjKD7NfdTjpv2y3IH8b8kCX4JzvoqMrLKy/lVCYQ/hLWzkm/6nNFKbF/D1L8idTUXZNts33m+A0CooAEGyuqXOcF0pmZR8CQAS+CbH09XeoWO5Zazu/sULQhf8kPyYyiWmv/GTHZVOH3ImaY1S+nnVZR4e3TEqOnUa3nGcQgojSHfSQFRruqoYsNRb3TtDUEfZIlO+SG3ptftiBlglelMQ/ZlXI/yHVcA1f/rLug3rh3BF/jaXzdi6E66sU0VEoD6yDvJoc2N+Bu5cbr77jFBwbLRPFeLiTTG77h8eJsGrCYpym/D8CmjkjQdUuryNvbrln/EqU4QADoaxPvOC4HNVdGF8bYTW4J1j+1ysblzIhVsECPLkdrmIzXc8KZivm6FGutOGUbJESRiMMs8InK8U8QpTeZHPm8I2EW64gPbVwCkV3e5eM4/5THGBlnKV1sdQzn8xvX144Bz8PLfg14rNsQ0BrVlczVkrWa1MjvopXIECclnMKuGku2eppZ/OgNG0XrDd+gUnWcsi5IFMGUzfNqcCXMayKgm2P16TYiwJwzUAhkJDADmPCPW748i3ISJCOyR4MimiXwBc2aFxL4j8uUTB+Tt6EAh6MVwkMsYdq3hzWXRY73E1oQFsrOvD4dyZarqtwiqwSo8rkPgusZnm2XmTxTvj7TshECGFQGNu8NC2wyM9tf3laKgqIxprOyvvQ5GHOZvHTV8PNz8Kj3GLcZh5o4qE3wDIsiTCBxa0jaJaRMkycx++CJY90ynymes0rOzeamgR3pdZzBhvYARWarJcNUIh2Cl689TYd+9i34dfVxGBLmWCBjk56CuyOVnx40xIiPu2pVzFyaLLT1/5VpnUpd+5odLFKOdO1bZc=","layer_level":1},{"id":"e0c711ae-a334-4b15-8ab6-68ea839d0842","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"标签管理","description":"tag-management","prompt":"开发标签管理功能文档,详细解释DataVines中标签系统的架构和使用方法。描述CatalogTag实体的结构和属性,说明如何创建标签分类体系和管理标签层级。阐述标签与数据实体的关联机制,包括单标签和多标签的应用场景。详细说明标签的增删改查操作,以及批量打标签的功能实现。提供标签权限管理的配置方法,确保不同用户对标签的操作权限。解释标签搜索和过滤功能的实现原理,展示如何通过标签快速定位数据资产。涵盖标签推荐功能的算法逻辑和配置选项。解决常见问题,如标签冲突、权限不足等。","parent_id":"4bef343b-e06f-4b02-9a82-ced169b015ee","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogTag.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogTagServiceImpl.java,datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java","gmt_create":"2025-12-25T23:41:54+08:00","gmt_modified":"2025-12-26T00:48:00+08:00","raw_data":"WikiEncrypted:sAdMLjEpcxajdAKOCNqfND2nHzYJkziLNMRbARNqKOiiD1chaT9YJFjQ1LUAePc0vdgoAPt3Mkb9vFdRsJvNQYRl960kuXVJrtcvWIt8dzQd/mzjw89ToK/SWPz/4OD6zMgSUsP65Cw74e4geAO68Cz66emPbsCaj+rLa1+vCCNw1WROfSTekQsagYcWGeKGycD9ctDRX0J+okS3hUtBFQX7QMbKpFdn5torgzivLn0GXf1Jb5sGQvYV/lStqRAyXY9/EwzFinVytfvFxF5To474s0athUgC9ur7PQNZlV6S3Sj29KHvI0Lm5okdFy9UpvF0CskPUXgBBnv7J17uOg8TP7xtEPLqGpJ8A3Z/wZT2oW8ZVQU1O5kCUZdHFZOEiPck8W4MsQfL62tqYQiM1hruBhYKv42RWgLYuhQPzGKO3BEqSH0nMvjN25uYRocETiF6uUz2Cugl1HjPlbkkd4FHXkFH3mj1UXGJIxai3ZD2tdspCGhDZ4vpcLNRn0dU2im1wAQt+cJ/e/huETKaURR/e7GHTt4ZYgHZmahQ5zEBbRzCghqt5wSbTNsulylcCmgsVwF/i1+t5vxsds7K1ILQvlVj1dntAky9hLeIQUe2wuZFDRE5nF+YYl9V0kt53Px89mtSWBEdAQpCOdVhR6fVQuatSRf7Vhq4zhK0J2yNyFildVLpm2KRH9yvEuky6kLPKKTCRV/rIkZXYZmk+61bLpLI30d21mo9yj6KC6gWdjxLFl+aID4W3pETqnwr31HSMAMMNBgmjXCTCpitgoYBo3TW3C7aStx1Q2yQ06xwPf7MIzLfdMTw31vdbJ3+ab8tWJdp+yrQTQ6gnFUWH2BDwQC8fh5pabIfSk/f/EV2BDLMFSCWumIoOM4oT2dhfO6FMaWaQWdVbX88iiA+pnH1STKMNychmTH+wG31cPsrOi2aB3EPwn8BB3GWD7PbOCXfbNX0x75AWp1QiQ4rEyfITq7HtuLzrU/jGm13PBnWS2CgR3Y5eLOAsaZVGHPBZPJqFG3dl4aa4fx3pGIreqhKiGmD7DRoQ+TFNKDYgf77RBBac3spcZwKvyfGiz6rRvv1hqOhDF7NrHZXo9M6v8V6W50U/slUCe7JTFVPcVrSI6CB6pyQh5OZhp7Gy8Ea2ar7MQ7iLsEdcEbPNYCo9JJ+YO2/W/65HTf5f9Aojuj67nuMZkxyW+Dt2UU1JGtnkoQial7RUznf3VywMfAEFKkzlYC76eS7m7r6oErZcyNtZNFqM1I3OY5BYV89OhB86teUCFE0KbR9mzqHm5fCC/b0nx64Esw+TIGre45xnytgcokW6kmSF6Na3uW44KLG08VbROR+7pF4h1L6IJDBVneO2F2HdyQi4BLEmrQZIUnHbML5pqQ05fuuW88dIEvbys31g+JfcgXzUDyVXTcEAIe6Hr2rI/ca6y9as69JX7MQC+Vw23mPIgbMsGZS8jP4xJM2zh8LjTORpIombUS7kghNqymtQbPgbGCyaAGOeeeecnWQdH6nLxm0l10AmAqw/+joQVK/YUgj2xYuGUlPhLmplHQAqGhf1Fn8n/SFT7Q=","layer_level":2},{"id":"74203214-3316-43ce-b2bb-545d7e140a7e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据库配置","description":"database-configuration","prompt":"创建数据库配置文档,详细说明DataVines的数据库连接配置。包括数据源配置、连接池参数、数据库类型支持(MySQL等)、初始化脚本执行等。解释如何配置主从数据库、连接超时、最大连接数等参数。提供数据库性能调优建议,如索引优化、查询优化等。说明数据库迁移策略和版本管理方法,以及如何备份和恢复数据库。","parent_id":"5d2798df-80b4-4ceb-b66b-9167054fa556","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/resources/application.yaml,datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java,datavines-common/src/main/resources/common.properties,scripts/sql/datavines-mysql.sql","gmt_create":"2025-12-25T23:42:01+08:00","gmt_modified":"2025-12-26T00:18:54+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkFIbPLS24lpjasA+uCz79jMeOQpuJhuP44OLRhCn4MTH7aBT11DiXe6Thcw/3YSVSljUQaerqDo4ul722xf2rFYqplnGB6PnUoM0SVX8tU/r+LRMKpvbb5ibmeJ2OSw8GYhv2lbQAJv8EkhiE4Ex4YQ8WJo7Abn7gKGyVapYiZ9+W5aSxsPNYe79VM9go8hqMj2zUBY5Mh0c14OJGjTP98Hzd28WHo3fMZHuky5AGsFuPiVMPGlBtEQCt+pt1oYZ3tP1WSdwS6Uk592bWHseVwK5ZqzIn+7aMEKeNfrUlssQqCf5NXgNXfcez3P2nUVbHbcaIqfsUZ7QuA4u0jX5hlOfSl9iwE2rHyS934gX+fpNCuafE8eoEdhC3N8dVBCtzugxeti010yVwep0m3+KHe1FAnyE7QRjPyjfvdEdaLVhYBo2bX3tKhBjFkqpSeUKDAKcB71bDehSADtmxLl1LEHiaNQEsiCY7awbOVLIJUauR5Sn+lK7hDCZngRwO0JuQvBPPoFoACF1FBPpZZuEIiB+MlFplERPCQeyuQkOCIp+Lma8c3BGf0NtuI/V7fouSe/JKtlw2mzeI+83HxAdGiUaKUNtU5Y5l7AghGxDhLCqOdYCWulGz+fHJ6xFHB8edezgMErod6gnwxwkSuCA8e3ljvPWoIV8s/ZV0Z4d97vWvdC7/T9m/lVjusbkmfNmW3SUhfHkH0nVoNkWqhUuv451cg7reIfeGmFvAjv2nSG/slo9rHifJ9S2+k8CdkOnbZDFGhZtCDIQECVwe50YBQwPWZVIfgwcorsYnT5CxDx8NjMn+mVhTbUh1U2vvs+6xvWfdUHHGFE5z1EHs0VfSa814JW4vnaxPxcvzfuuM+HDr2xAf71mlT88eg1wtdlaBRcwv2w5FAKrOgSl/TNTo9F1LMaOzefq3fG1azW52zQobSg26uEcaHRsxzlWDSu+a6tcV2S6xtBx2Es3tDDw3UECjsBEAJCV458AZufoHPoPEUzu1Hmk/kc99jusKO7u6a2gYzm754Ax9mgr2ePrsBtptEkzDHpxZyNeIsnMbWDGYpEew9YfPrrGFF4MMILMqMM63rYZwAC08PK9Ngo3o7vIDsHyd/31GF2PA7KoxdevEVLkd8vrWrQ2W9SbzKE84dbywEW9STqAHF1sQUynOyfms4Mc7vpES/pjqxojrL/HQEu67biEwsWhpLlfXHVjUk2v59k5ASfeExivz/MXnzM=","layer_level":1},{"id":"d3911c90-857b-4391-880e-b23a3893ee7a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"采集配置","description":"data-profiling-configuration","prompt":"开发数据画像采集配置文档,详细说明如何配置和启动数据画像任务。描述通过Web界面和API两种方式配置画像任务的步骤。解释配置参数的含义,包括采集频率、采样率、目标表选择等。说明如何设置增量采集和全量采集模式。提供配置文件的结构和示例,包括JSON格式的配置模板。解释配置验证机制和错误处理。涵盖不同执行引擎(Spark、Flink、Local)的特定配置要求。提供最佳实践建议,如大规模表的采集策略、资源消耗控制等。","parent_id":"43eef860-d2bc-4625-a145-101fca77c030","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java,datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java,datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/DataVinesConfigurationManager.java","gmt_create":"2025-12-25T23:42:15+08:00","gmt_modified":"2025-12-26T00:47:10+08:00","raw_data":"WikiEncrypted:YZI97ep9QXDPfRNDXs4+JGwAht1j93lelyy1l/cm5MsH4BE3wQa5yelBT3DmE2wuvRr026XBNFvHEhQMJSXjlBDs8P4wj3ISN9n7l5Lk92wWvNmNze329rN4neOkviXEpv2eeiixk/YygzkIySbxo+GGIEcrFje0UrnpByptAkOsObOGCgkM+T1iga5foBL5RFd8Czlm3H32M/AnDHkHRXxW5Re/ZqFnIlxVlBdpvx8WbBEsf9ZljhEVtsXOcNlAD4xotuWRGd4AvnbGznJjM7xP7L7vnJGZdQmtLA2IRRPPfaq1VpBZ89yno9ESJGRKBdeq6jiTCqJj5zZLfA8NfU+XipLkPBWmdeMbkKGwhuKr3Oluwll37Nrdu4/KriizjFdHfbgbd5Q9OHegWSrVf8fvMhNxrYq6xPYDGHiFCtMKJDYBUSxnmEWu9gLgne7sT9gRcvsZOSAXzOw8deCzMa3tw3nIMZSTchT4hEMnwMcnHBeBDJZRp6YmPQYGqrJkSvwX5Vd3h+R9SAleqLTFK982vCDMFvYBN83L/oGCwKuUNuFEg9y8zkZnqKATu7ui6pGXO2KqdXtQ06eAaWUd3rA1atjg9/AStoi10dLsB7lAmvxQZpyyf0pw8W2kgZ0CgwTHROy35eilTREn+m+jZ6Co6F36G+5dXUmgmFVCJf5pE2/U4QnfwEzgJA6BVizj6GgcOkqZiXH0oPqz8ZCJauVT/EzRcRaw0hBfOgjEv+ppNcGf+B71NDcCWTVp0KZiUSzZU2zDBpQsIrb0CpTPlaOQTAH40CWxnXW73LRbmOxrSo926P70w3I+pV0Bv7CJvctv9x5oBwRakx7bXKt4DYqnj4VvV26nQdNgBwvs++hPE+odVSB6VVcKmOUUFxjaEvzHBncapc20FUN8iIKIV7HFK+O2+cpiWqEgvHb7LF0rkABjfFxn6xMWT0nfXQuxWFLC/T3O047J1eM0aBcIpca1Xd43CNzBYzKM8o9swsc1svLVmhXjyJLy2+LLWNYnMv39z2X0xuIq9ZUl/D8RCPPkSJloASzKF20No/EA6C62B4z281UzqWPTntzSOjclVXgw6sfDzOSBUoe7kFH5nFw5VvYOXxUMryZtuhYyG7GmBQW7ObAOmWk7LCYNx91FwUtmlgrSwuycH2ImKAECow1jnBOyBlaB7gb92UVFD1oeQhjT3UBHsEn0HlfBZ0QcBQc0cx8WP2Y2sxapg2oavUR6ko/XXkxjfDDN7EukvJomslzr3Pp+UzusCtoeZSp19bJmMD+INRoZpnDiETjWvt0pLjBtTD9xPNrFb50YWeGpWsfMozfI7Ohu6TWnKf2IrIWDvkHSNxRjloFof49WgGYo0r+IMia7VLo59I/WzsGqoUCYaDPRTvIDkJrGiF5M1hzb4KcwfzVD+wvZYHZacEUp5D5X8HQOICnLwfyyMLrYkZ/JMb/vPaNncK49u+PSG+YFfWSDiYHOXVwpMgXGqeskmoon0VOzEw6m6s1nj6g2ZOxolcO6tOGsPmvEoMdG0jEAWycyM0cIZa/NldTtsQ==","layer_level":2},{"id":"42102899-382d-4ae9-98ea-ab19ba59b352","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"组件交互模式","description":"interaction-patterns","prompt":"深入分析DataVines核心组件间的交互模式。描述从用户提交质量检查任务开始,Server如何通过Command模式将任务参数封装并传递给Engine执行器,Engine如何调用Connector进行数据源连接和SQL执行,以及结果如何通过回调机制返回Server进行持久化。重点解析基于JSON的参数序列化协议、RESTful API通信机制和异步任务状态更新流程。通过实际代码片段展示JobExecutionParameter的构建过程、EngineExecutor的execute方法调用链,以及Connector的executeQuery实现。讨论这种松耦合交互模式带来的扩展性和容错性优势。","parent_id":"7b49efc1-5641-4ed2-84ce-ead796da0963","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/JobExecutionParameterBuilderFactory.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractEngineExecutor.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java","gmt_create":"2025-12-25T23:42:16+08:00","gmt_modified":"2025-12-26T00:48:54+08:00","raw_data":"WikiEncrypted:nBJhxUtob+Ed4xp/EVXyZGQDaNMM78DP2O0/L9mN5PbgWdQlJbB3IWUWIZauaGTmuUFiAqcbHWcMR/BoWqPkKb/AXerRaGrsodxN4I2UmwEoC8n9yEYT/lyyyGUi14iUQqeX2PgIBbaUGQ+c6V5At6VP7nqYbA5P9UhmERr/wZAgAWR86dvxd7xb8gVTzfTq3WiUcWN+/s0mgGOdNKK10R5k4fez4WNYcDRzGVoI9v8lDEYKvpy8fq4+7t6o//PMppX3guHkARgaT/piUy5mq+SPNqCrSc75qEF+ivY+ATkKeRLi3MoE6IotnmrVLmET99Gggirq/YPvgRBd91L1Rv5eBWewxEnoSDBBEyyTnS1pLX7CPoz3qQqlF0bihVo1jDmrTE8Ve7FNzp0jpBq5QW2NmWPyrKYWbY+LeQ8jnl6WaO7zkS5ZzQ4vcgs3Emp6s6fVdqesy1TQFBvFl2Qlj3UzJsaHQ7lnn14DbMgnh/RgwFdrcBLPDVZQx2Xp3WjZ48qsrgM4Ly3SF5sJL+PeurFRECP15BrzGTC1Xa73WUMBdtlR9GqFXzUFK/T7DITRXRb45n3ldhC9MRDPrTPn44k0TIbt8HXeCaxJy1wGEp/q5xXLtqtlWXEU0Rqf5pigRaRQjApJYLEnN9KTUlrUN7pmo7alwmo92PKv78UkEzzIlqIBeGFBuMiWXkOdQ+V9IhB5XQHNC4+wdwCteCZ0InTJTuQFMVxktlGUEDMifj5C0Mf2QNrWExeBEX0aGqfwdTqtFkPzVW9f56LvHJbwRwEKB1gXYCuR3sPWGo8gy7gyB9bphIccoYWQkIrmZRhwpv6UhQXNeso8X0a6k3b6//AAmZ7ub/P51ql9E65MoTHK7XIdxTY4FDM4wGs1a1lEpvpX9beSeSiLpXKkhODCbKn3dcaZ1LPZK56cIP5x1cZGLrJcf8MxLhqblq65gO3zIR7PwFZpMzAhdqpG9osb1y2w+qZS7lkKG/O8tZJXvX1+k8Jvg9rNzL1FrUvpJ8MOElepso7OIYpgzHK4u8tiyygMR2J381MNaM/kEyt1N7I24TXaGJhT76QrKxXAjLu3kmV+Nwr3F2uhH8VT1jJvL0U9ypv66jmI0jj/zTpWsPQ3Tl2IAM6uzkf31VIF4/bRZdYJpPWCCnKTb91SjB8aoXQoVyOtUjUm4we3wuRCOUzONO+Qclgd5lyzEk1HdCwS5aek2F1KldjCkTLv+kRV5cC66nGftWZm3TvPVqHt3bYiUYkiSqlNGzIR6ES196BsAfMvwxiwqdzq6X7JWmEMjlrz/Loey17jSCPM+KyTFvJzJUBnz0YDobMm8Q1UKYcPqiDZLgZrNP6lhdNs7owd9uAp8XIMGxNz0LK/pppUQdj9nlC9wTLoHns0n42FSntchBr2tUoUP0Nj/Rl58y+V4hGNK53ws1uptkUKn/nJ4HL9nvmfRAoNo1DVUg0zriWUGHTEPoMxL64oXEfD+JBlmWsBl+s6/beSM7yyYm879vGUk7syHckoEoSeU6zFxYrb/WfWQnPcdWaBXZHJcZZHsMfVw1aiekvIglI/oQiKCsPCYwXvns3rejBo1POw1Ruax9OGO4W5ooTu+aSrfQt97wuvmw4Yxo8BKM3sGRHwOV3WVmYXQA6ty5svZ7v4XauC","layer_level":2},{"id":"9f664f1b-9947-4d3e-a6b9-ef1a47485c24","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行配置","description":"data-quality-execution","prompt":"开发数据质量执行配置文档,全面介绍质量检查任务的执行环境配置。详细说明三种执行平台(Spark、Flink、Local)的特点、适用场景和配置要求。解释如何根据数据量、实时性要求和资源可用性选择合适的执行平台。提供各执行平台的详细配置参数说明,包括资源分配(CPU、内存)、并行度设置、超时策略和重试机制。描述执行环境的初始化过程和运行时上下文管理。说明如何配置执行参数以优化性能,如数据分片策略、缓存配置和序列化方式。提供不同执行平台的性能对比和选型建议。涵盖执行过程中的监控指标和日志记录配置,以及如何通过配置实现故障转移和高可用性。","parent_id":"a19e7b20-774f-4c69-a930-24d3fbcd2f0a","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java,datavines-engine/datavines-engine-plugins/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java,datavines-engine/datavines-engine-plugins/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java,datavines-engine/datavines-engine-plugins/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java,datavines-server/src/main/java/io/datavines/server/enums/JobExecutePlatformType.java","gmt_create":"2025-12-25T23:42:18+08:00","gmt_modified":"2025-12-26T00:48:42+08:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"a30becec-5d62-4211-a937-72611bcac877","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"插件加载机制","description":"plugin-loading-mechanism","prompt":"详细阐述DataVines插件加载器(PluginLoader)的内部工作机制。描述类加载过程,包括如何从classpath中定位并加载插件实现类。解释实例化过程中的反射调用细节,以及如何处理构造函数参数和依赖注入。分析插件缓存机制的设计,说明如何提高多次获取同一插件实例的性能。讨论类加载器隔离策略,确保不同插件之间的类路径不会相互干扰。说明插件优先级(Prioritized接口)的实现方式,以及如何根据优先级选择合适的实现。涵盖插件加载过程中的异常处理和错误恢复机制。","parent_id":"a8f7f5d5-bf23-426d-9273-02f47623381e","order":1,"progress_status":"completed","dependent_files":"datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java,datavines-spi/src/main/java/io/datavines/spi/ClassUtils.java","gmt_create":"2025-12-25T23:42:29+08:00","gmt_modified":"2025-12-26T00:50:22+08:00","raw_data":"WikiEncrypted:ukPV2tcWPRGn89Upsee0BNAEuZMuf7aEymPrqapHdTOx9NMawUFc+tT13V5zRE2ZcGbJUQW+F+fRCRsGuc6C3WJlt3RXLqVOmJnKsce2Wa9oIKNujwYoXCxKa/rHChj3JNR7dDzKaa6xhPnBtjeZ4f98KSMPyefDwq0SnH4D/KowLLqseWElXxm2T8rabpSvWCA6VazIzhUHNNHlGBuRVtt7uqw5KFdw28Xptbghk74at2H7CuSxwqNYjuJ5zA5XzvgMUc2mluCp5DGwDFRQxtFpaahzXcNCPDksKeAPGS64Rdw1LXmrwxsFzs/hzZ9TTuKj1CL+BrvuCwwMczrkjhsgXFEtqXnICWyK9ttOMd/NM8AbhZCO5DYp+k6S/7AaYEMBrD8MlkMgoBUqNNvVe+090HnYVrvwUSJ5l4zO3O2aG1PF3eXJoSfzaxfkzfhTUigkoQtA86PLo6Qc2fTqm2ZjTx3d0GlVnP+IXOA28IMHxTwXhqkPaaRHzWP8L5RKQbVmHj4RmHWUc0K3AiQ4HNkH9M947+8low6eqvGsNmVHHjPWeWM1Xu+NpzkLoDRVolHQghU/7o07wL/khXIm/EzbB1gb7cKJhtMxV4f7/9Hod5vimWOHiXbnJ0FKaUBZ7eaWaJfRUFSkkQL8mvOoJ61x0gnTWW0areJn3lmUdEyTIZMLAcS6FmdXqzGBiWG7YsdhWjYQDNben1a+0BUql0bx7y5o8k91XK7GNeWsZO7u/KlyrCJA8kC3hdy8nQVEQiqyoZAcztjL3Ia/EQ/rrKP5EwDDUGHVSwTs5Ii5+hkaUESxZMGoO7PAT2CscwZAnkzBiLyWsjWPvSNDOotuy9F8IQiIC/OxAAHqQmsDdbfaAHClwF9stm7n8t73KqfvYLx50o1wEyOexy2XIf65jKJcSMIRASD0OoPMOUh0DDRcCBBI+mvwRm6BIJYL75ETeUFwJO2cKa0OqrSpxr481iEeC2E2Qw81s0h/DtVXy5CU1gwuHSgdW3y9uIQQPEJOF/u62GTO+FKdGH3MPSoY0w0Ycasl7BS3XRW8H3QyWb0zfqT/RJwivPXk2coiho9Q45i9B8WlJRdR9zu2q1F8nHSE0KVSMZN5HWGDWPphCsCIPdLeHVxKZ/jdObprm7ORPJZIGfrxkUTtlpHmVnY2B42LDoaC+jLKODm0xGwvSdL1tZXQfnK2xhO66MvlnwZFHv99nuK43RcoPLmHg9VUPi3BOIqzhy2Aw2h1SOZX0t0=","layer_level":2},{"id":"4abfa320-b04c-41ed-aef6-bfdc2fe13c3a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务调度","description":"task-scheduling","prompt":"开发DataVines任务调度文档,详细描述基于Quartz的任务调度机制。解释ScheduleJobInfo如何封装调度任务的元数据,分析DataQualityScheduleJob的执行逻辑。说明JobScheduler如何管理任务的生命周期,包括创建、启动、暂停和删除。描述调度器的高可用设计和故障转移机制。提供调度任务的状态转换图和配置示例。讨论调度性能优化和大规模任务管理策略。","parent_id":"4e0ed203-0047-4f0e-b2d9-d7fa1cf34621","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java","gmt_create":"2025-12-25T23:42:30+08:00","gmt_modified":"2025-12-26T00:50:41+08:00","raw_data":"WikiEncrypted:sdobwW3Qsckh0ghPExsMqkgInHQmajp2nUSs4Ao4ywNv3u4ZW2Jdl01U77lfWOtGy9up8xL+e7aZHitwnPxf5RxdS5z+ZBJgcEFVE2gdvZTXMgphiU2ooooW1nQjoW0NEE/eIGxXAYJYhjVgmEg1mLttzwybDazYPkr01r0U6vU9lW5lV+NABMIQvjnvGvp+VxhyfbxJ0wRChbjUYEMuHaNOGUQ7j8gcItBPaLLbojJE7FjC2NldicujWabP/J7SK1L2jCMP3FMhXAltJGvNkAo21oSFcfxhxfTV/yZWr61Cn+e8mc555tnDoGEy4DwM1+xkwYYbIejTWyF5jnKq+YDpehc4LWpwS5CdTpfPH6Uw9r1Ik/CU0cIr+LeAjukRpn4B0AuYT1cE3aP21FLNyhUPe58GK0O6rnB5ishzdhB576BY3NCjjrB/uLx3S3pBLzXj4LmyT6v7pyeatICd/L7uJWdaIJzw+l0fEE0ck+WlE+JbazP5vrb4fBxJ96P8c2hMGdWhmjking6J1LRMwlYXjcBpTaiZNGQHKM7xixDudZ2uccTBz47CoQgCSFz5UUSbeeHxb7tIojnRsNyIhb9E/UMTPxO4yl2xmDn/vTDpvBrU1TeW5mLctIgNLpg+nseQnQpxQfWYOnZHyvz/K96+QAsdT7FGEiJkoRsaqm7/VpbsN/fuah1NBAdygJizA7ZHiHOEk3HNyD06z2uAFwJCMg32biDRMr6anP6NsEquGLYRw1OYiHsqSPYjIu/YPxErlqXMoNtaUQnPrFhEZQ9IIgoszsXF0oOI4Fz9nDTsKFJLiRdYpJ9WuGZ7nZP5tvrdFLds501ftaj/AWLLyeWkBWwpZHW5WTLJzlk3h0GXbfQ1s2XfxDyavp6H1yECbmmeYlJnQ75daNqYWmXpU2hER1hz3O4zc791vXmWcGgXY0sP5Fvewk+mwKLm7PGZ+wu8D2RTqvA/2XQEZfhMTRPzf5G5S3jORDaWQcFemtDlqeGWmvA0GFgIkSMqPoA7VJ4ekI6+Mgr4RHLvpZA7uTzqQm7bFKMgDM88ziuYQF5tLHAR4zsShqZLY5cuddvhPMFAEYVYVcHA5DvNPQN7TgKLXwDMRiFqTkz2G4C3ea4YclubMzAnaYfpQ5mR7FYya91f4czNb4VzN6WFAlEgShaJakqtwrfOiXO7h6y0Zjm1WY0GvnVtvgNOQqdhX6J6vD7KlpJ5UKKrr7xFpqauRrgeFMP2oOiZ+c/h6d/CFeEfnvO7ZjTTTmjqaGMXl9e1tht3G453ZjyALIwZ65+SqGYzZVrB1CBNY4z3JO2rkwilgTcXaD76edZvHuzUuP3m","layer_level":2},{"id":"968acb83-28f9-45b5-a177-a7764a39a2f3","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"调度任务元数据","description":"schedule-job-info","prompt":"开发调度任务元数据文档,详细描述ScheduleJobInfo类的结构和作用。解释type、taskType、datasourceId等字段的含义及其在调度系统中的用途。说明cronExpression、startTime和endTime如何定义任务的执行计划。阐述该对象如何作为Quartz调度器和业务逻辑之间的数据传输载体。提供元数据验证和错误处理的最佳实践。","parent_id":"5856ff4f-874a-4522-87cb-4ec444ac1aaa","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java","gmt_create":"2025-12-25T23:42:43+08:00","gmt_modified":"2025-12-26T00:50:27+08:00","raw_data":"WikiEncrypted:Ixm4kI/Z7v0V3JxitGlz9Yo4nvzQMkH9lyYtdvH/QHC6EuMAHmao+XxhN73k8sUn6wyAkaNc0RrgXjramLRH3R66tXwDXBRWKsfeWmK6SrURn2ZEP5fVAs7z1qjp3MGwEJ5QXCvXcSk15/y7/Tj8zQMMApPznEhGuVrvhiwx+JugC3nMdoU2a9jd6Uqcheq4KEFuLVd/N2mD/ub3xJtfnRwMr40PLDiDxWdWnHUZ3BpD4B+d1u2it2sE0tbmJbDKXGE8B4NG/lLvRjvYgNvfP/Z3uuG7AMWVU5cZA7ONT/oRNsEWUC1khJY6dY9D2agjtGB57cqUGX/t1h6fRH69mhWLhK1p6RE4rdTaJpdQKO7yvHrHQprHQVdzmb34vQ/Rb6kyR1owq9kr7eohx4BZyhDXzQMbjnJjmjjoBiNDHVCRcFPtmCMO+AAJggLf+AkRhRV3PMJ+4oYqsJ91lP94TW/Rcf2G55nBXSkBKob1e/8b1biPMSQUQivTQVQ4Q7PaYZhkBJEoAQzu9fY+ZTxGXi4vHP8Votv4g6/q4DMPCZYxWnZAO7WTGWNvYv+Tf3rEIPhimzYpblewP1qpgFxmj5dthauHuwkrnRvR2bmvRswWmElxl/arZFJHlvHCT87jY9nX+q3vWolzJob8P1fP2pIiqeavmL5lQLO+emfpMyixweWrj9wAoA5FNzUCoc/MkTsw9l01unO8K+9eF6P3nz8JaO3eLdOup5KJ45PCHq/6SbYlewqw85aY6TZNYO/i0fuBxvUa/4diXZ82t7indnkadqQUJwxC5MSSnK3KNICC7dTdoi/kbjgtdlNdV3e7gYCOXXNGaOE3Z+t/Uc+Vgyc0l/H3GD3NUf459joIOj/WaoPTJKkZl/nEpyDwGuZ5","layer_level":2},{"id":"b4b2446b-5ea0-43e8-973b-48528c40559d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"ZooKeeper实现","description":"zookeeper-implementation","prompt":"创建DataVines ZooKeeper注册中心实现文档,详细描述基于ZooKeeper的服务注册与发现机制。解释临时节点的使用方式和会话管理。分析ZooKeeperRegistry如何实现服务注册、心跳检测和故障剔除。说明ZookeeperConnectionStateListener对连接状态的监听处理。描述ZooKeeper客户端ZooKeeperClient的封装设计。提供ZooKeeper配置参数说明和性能调优建议。","parent_id":"da4c595f-1508-456b-b54f-fd0b5324fa43","order":1,"progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java,datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZookeeperConnectionStateListener.java,datavines-common/src/main/java/io/datavines/common/zookeeper/ZooKeeperClient.java","gmt_create":"2025-12-25T23:42:58+08:00","gmt_modified":"2025-12-26T00:52:03+08:00","raw_data":"WikiEncrypted:DU9QY7EXJ8zTUfNnhg9yV4UtI0Rci8wfDf+0S+29OfypvCcNwzV6gghExkjGmzTOXa16gGJMEH77tffCtItJ6qsyu+Q3QtQKjRO53zoaWmd/j/81me31j46TvRPkR/+M6i8pELxitzMlUQmDNlAhfSUnG0cA5Tm3RuXSD5C4hMEvxDSlZhEqB61hN49pERf6KmxtDLdCy/+7FGY9P0Sce2QXLeUaH3Wv2ZzVhCkTi692Hz85QqCRn5WEvzjBHZS1Hdb1LpeUgjZVb7bOnG7jITBpD6nFfis48/1T7wnXUD44e7WsJXdy1JgtRQ6acHakFoQ224/XeEh4r97Etsa3PITvuLmTk2r0ImZWtXzeo/xu2+TSIssWS4FB47/mH6EEpc583rdvTlEizuslt0f7KphF/U2K2Hj4s5Ey2WyRFMAJYL41vXlKn/QtTcbFAy0PYEs5bIvoWhBi4/b/LXlIYV3ED2czv0auhc1HHKlmG3pzXZq2Hk3gF/RbCsnSz0V4/6AD1OwAPps0JXHcmDWf++mFiJf/6cto5CQY+ccGmFsM6CYRP4Zy33SXlK5xzzdVmuMJOOhJFwxrVs9C4vPh3Ol1KDCTgc1RYPbfFoa5r1m2Q933Xl72GmdcpynyinldxW1tzkFmonRO3rBCDbr9M0aXBdNajy8I7pA4qrScQXujM9Bofw7uRoYKPCfu2OYlaCq7EHr3hyuCiwMI7ogadU6bRAnNSKujS0zCWHB6Jg8ac7ZZRBknzI01XE3FPkbOXrUyZlsNGSUGCpJ0dwcH4VocGOeXzxMaGUwLUxPNfwB7Gty1LZ54Zv4GKWaV/HKANVJOPUQFO89dyYaofUyNikaB98pF19NIUN9vvlCfHgbch73Sp0+qDYFJpIbAgRXZjq2sabe/o1v716380G2UefmVn2DdysRbNuAuc5gRNyT7FfABjIe+owW2Q9nnJzaikxrcKQCj8+Vi+I+MZuOYlWy7mQ3LkllIs3akydZdSZTlVvK7+scGcHe7THt6WPsoBJJDlIlfdevfzVG2kkDe2Epl4mdp8u0DbYPw4DG8fi+90uZm9FgVEz9BfVM+Mho7j74HSx8E1wu3ESgyORNO4XU7gomlfIiBDFMifpViMN6Q7d6KaEyEVE0Y8AwaDyPEp/IeVIkdxyQk1qJYX6wxKBcam8XNHpkWl93BywIrVETuAaqtzrhnH9/Ty2srDDS+GbYIvrIaRzi1a08+zdGJFprYKxlyB1YnwME/7GLvBpJOPV8rfnk1AIci7IqXN5mjRpqYgqCPUuAwlxhOOveD/nk9OfLFOu19a3DVXoto/dI41VyNu1X3Hjj0hvt+ETYvjMq087fPng5ovN4YY+Pv8A==","layer_level":2},{"id":"251acb67-6d5e-45eb-b64c-94b11aa2ce30","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"REST API接口","description":"server-api","prompt":"创建datavines-server模块的REST API文档。详细描述所有控制器(Controller)提供的HTTP接口,包括任务管理、数据源管理、用户认证等API。为每个API端点提供完整的文档,包括HTTP方法、URL路径、请求参数、请求体结构、响应格式和状态码。使用Swagger注解说明API的使用方式。解释DTO对象的设计,包括BO(业务对象)和VO(视图对象)的转换逻辑。提供API调用示例和错误处理策略。说明认证机制(Token)和权限控制在API层面的实现。包含API版本控制策略和客户端集成指南。","parent_id":"6f063aa0-15d9-4271-80a9-edc58df4f3ac","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java,datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobVO.java,datavines-server/src/main/java/io/datavines/server/api/dto/bo/JobCreate.java","gmt_create":"2025-12-25T23:43:03+08:00","gmt_modified":"2025-12-26T00:52:02+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjDvuBdxJcNwm6ws52UXCLjkWx3x4e7VExM55ApBIx5bQuAW9FCr6aVuNaCl8beDG+ydE9/nu1/rtC/CvdhasMQv3p5s7uBUDd5+z1gxc2EpiDOv65bjJ/Bp0U16h2KvJfhirsf+Pv7e1Zlo69t8Kcw7eUmTEvliEaGEBJU2nZWGnNddJOLeJ1oWqq1gvnxtTI7u5qLIoZePkt3YxucOKPMyrLAgBL9XywADWKb3aCnbXeIgypdka8RWNoh791w14/+0BhpVpn3Y8z5K+R7XEfJTAdoVzAoSh+cceNxLmP0P1CnRbrfyWEe0CIIPmzGtFv+1qCkqh27yneL1qSDhpohtUcBLgXdLNUJSOBcU4U2qHiU1UP0reXS2H6ghPAroq5LDdudXsaMnOhoYBaEZ1muhfK1ZhD5vIZcp5jWq6v5YlDvr4NUFfkSbARpHCw88qyssmxCOI7VMfbDi7jcffbQzkpMz88l2niQd3z+ZbZfBdwUYaa7D22Z+4tJsLakPdW+KMDThssjB64vyHW/PPgnnQCj9oMPAUP+NDNAF02uMVejytSCbRJH2jDFbwV+cOmZlyL0t7UWlhD8vCQCZtvQi5EaxuAXr6NCPm/WIoIznRwW3YSjeGYikw0kLsMJAxFE1PAIBPUA88N6BDmfGlyir6cjHDwVrknibOghh28+oqCBwB9dM0JHdQxEkWCudCB+reQkgrWTT/auFOEzBMXIz/5ofVqQ5glEUnusnFZT0V2hSBtL7sUUxbtwXwpeyMoNjHcoOZszljFQF5qwmJDO8oRXLpVzUTtDy4mo5Bnqnjjxhfe7r8W7OJ+xTyJWSyqo4yAyWY7d1mmn5grHrve4UFXMgM+5OHFAcxBqoxoWkcB6Lq06XuOFDcDB22DBnl3xGBI8zbEhiHj8eqpk+b8SG7ykP63JumDfeB4sg66kUctm3wLIkNGwHbexpH3+gVV6MyNMG4WpD2/SULgaNovrNjF7UTChS93fUthSI0YbkphLkZ+UezpOZqG+taqI3PlohwCcq4FBAKl025RV8qyilNrt9p2XD1LhC5DCXJ6TaofZbSY+yP8zYGIHOR80vwnk4VS7YPVghTMGm5J7wrNTk169OlHvrc0g568XuFi97QRjq4vdy3IZraTP1I58x1Q5mrj+mxac2DWBKMr6JeBfXRljQAezEkDOycZHlLv1YEyiyrjGLj9ra5EbLnjkVFEPo3cRf5UlV010un3KqnBwOmc7GF1cQ+2RbgBSQ1LGUXbaoClYh1kAYq6+fnlyGPFWmZZ29Hr9ZxDlkNe2O5uVuqbRvu5Vekg5zoMKA6V0ZbT3UPbIhrkiU12AX4RqAnGvP6en2lrP380tP3WnhhCVVQ/ENMdb+glajr5P/5OyoZKABEaiYp695KhT9N7t2noyYRBbjwR0iGa/a5C17fZLbQTyFelXec/Ejrxw5cplZNDcNzz+9rnMGqr0W5a/oJFvRC2PCO/Zp9RQtgDVqR3HIs271UKTKyf54QX/tt8pJhFYSFVoZwkOA41Hy0y4V11tPc7kl8vKAqvs+rA/Ou32tzEFtqz3j4IuMgWVzfxCOL31RK93xUoX/KXeGs8NMQqyTrkZG2EySXh/vSup3RzOw=","layer_level":2},{"id":"724f7889-75f8-4bdd-94c2-bc5fe8255890","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"引擎API与抽象","description":"engine-api","prompt":"开发引擎API与抽象层的详细文档。深入解析EngineExecutor接口定义的执行契约,包括任务提交、状态查询和结果获取等核心方法。阐述RuntimeEnvironment如何封装不同执行环境的上下文信息。说明Component接口在构建执行流水线中的作用。详细描述EngineConstants中定义的各类常量及其使用场景。提供SPI扩展机制的实现原理和自定义实现示例。","parent_id":"bdbc7ff1-6561-4953-bfe0-96e43c8b3e3b","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java","gmt_create":"2025-12-25T23:43:15+08:00","gmt_modified":"2025-12-26T00:52:05+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJ6i3TliInoQU0Rf1tgG0VNHrVbvsRmzVYGYU0jvBmSaqlQO8aityzxGjGEFtdpv2dyd7PlC8XnIoBFum7oQfhvUdTHFTSZZ+L5370MrTlA397cWut7CvVleaVcuZYLQKMPbtE/JJ4RiNCjAsXtvCVm0/YNDTJT2ar/UdyuP0ducIqq5kBmqMqPFFSiFKRX3LnqsJCJnhNPwXxuKo31ID0XnrajVbjyVu8yYaQK8AXlY98FH8PR3009mTXxC3Ea71RMM0BxYBVnzuwJ4PBDA7kKcwuavNFwoDWovc/3iD0xO/mPkpuEDGD393Bf0l2386X0Ix/yE+PnGpEtEyM5DyzaXqlKF908aWbXgWWNKiRtRJvnk8BFbOPgPPpuEFeE1JygFjZvC7iq49MMHEfIBT/6+qlFOSN/bIn73ashTuVHBZDzi2ZKhgYXTnbC/szTBvUGe5udKhQFBioavbUJJ1K420zxpwRkeCzSkpcs0j1vqLi6YxD/4RmPFciHvO1soeGK/30jh6Z3K5X9s56VAF212bKVsJGj8uH7P9WCevx6HV93dV+8YlR2kbUCxdWe2ZsJE1G1n+M/ZSI7l79AXGFmIml2q+E75H/FmJ8cALFtjS0uW2xWU+meZQTG6CGOYTars2ITDTl270+HrcAowJ1dHI4YDDPRTF21tavAwcsuzn785wVM/33JppT971UP7Cgbwra0z2uMrW28qamgE5HUnStu7vjxcOGDDMJCesNVcl/vyyA8VzHYqccmaWP6eMMqlaL4/ykJmVm6yi5rsqt0ynzjHVddXPkNoW7hsVUJUrXahyECl7hjmnCNTXZCDOwzYhNo2XLNQUwZaDhHDSx+Icy8YCUxLShIO/pfkz2mODdITWr62mlFFxEIqCsuCTgAtWWqa4Rysj096XHF71DZq6ROgRH+qc8VvIhCLIzM1nHA36a3JlRa9WgIRxXe8vakHVxnyq8R9yoSmOtfzF6Pn3WC67r9g2XOCBO6XbsrVBIGL9KYIAU2ohEBnVgWwU3evs51ddZ+MJRlEpMdZbDScDdd/hTcSBKYRDC37PP7Va6dhWzCxsDkTNS82GicBJe6n7bwEoxe/LBrTpGywsMLCA4re2oIbxU5QyzLVA5MaProDCN5sdOozA3OcEs26TG51LxA2cn+bxTbyZZomYj8WLBPgiTtxcrhUV7yZKJZJpt8RJu5AigJZv+qgC5LMojlP5NG7HSbqmQyqDxgEZTgbQXJXSsPkZSwomAsxEoWZSN4BXI2XeRcdAOKa9VMJ4Fp30Gn9SLeZRq632lcf+BYKB5IieF3ihIwn0cGJ1HFYRqaya7Vv9gNeUw1xgHBRFEVaq0/Hz5rHRvdSsZZuvzzLiADWjv/Wu8V1JjzlGVAc8dBxkKD5DggR84xV0upae4w==","layer_level":2},{"id":"447e40c9-e605-456a-9493-57b6860558ee","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"JDBC连接器","description":"jdbc-connector","prompt":"创建JDBC连接器的详细文档。解释JdbcConnector作为所有JDBC数据库基础实现的作用。详细描述连接池管理、连接测试和故障恢复机制。分析JdbcDataSourceClient如何统一管理不同数据库的连接信息。说明JdbcDialect对不同数据库SQL方言的适配策略。提供JDBC连接参数配置的最佳实践和性能优化建议,包括连接池大小、超时设置等。","parent_id":"e4bd9d6a-26b3-44a7-957d-46e0c9ba5cd7","order":1,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java,datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDataSourceClient.java,datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcDialect.java,datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java","gmt_create":"2025-12-25T23:43:22+08:00","gmt_modified":"2025-12-26T00:54:16+08:00","raw_data":"WikiEncrypted:CSCHO1sRAUQnQ7JZNG7Q2YDSw/qLOUFQC11dxG6pF48fDiJNuP9ypaVkUZ/PBQnlraN3M1dVWKL0JI7S8eU1NZoFQMIJjBbVUFmBkN4CCM49eXobgiSUExQj6+Ftqc9FyGbqJtPO+EO3u2eBFigTMAUSFO5oAVW4mJ/Xh9p1zJSQyBJ0LDZVxqhFbdHIr3v2jKPmB2QbF0/1SL6zgx3xPbsr5ehNCFaBsq35l4hAhMeIJw6av39THvtdD7No4VST/CFVg1JZlza8OCMNTL3k1UJR5LJhVhayqWDbege+D/7/+pUWZ8szQFoi7g3zlAtdoDT70f/Va+PMUIXZhYxn7KWmQG3WZuDKeU2fcuz3fNl9VvLf5N694fjsPnez0bRBiFGIjBl9Y+cAT+IrqC04GdIH9zNPz6QNGGLllvyARf70x5sEFlq5GwSovb8/A6LrjZaNa7Hd7ndtXcpBgijjdchD1oJSUaAg/KhtymV1bI0cMazcPHRXSxllR0ZK0/t42HBtknWnbAyql4Jam+2ZmoBl5NJqTgp7SyUALFgpE/DC0ToXy3iWWUdk+M/eVmN5V/tsnjKASovHGQbrgri9Stii5ec5XM6XsRoilB3zc8xyrCtGMOa0AUG5oWbZN4le77ceVKa4QwW/AVf+a/KYe6jBftJwCk+PbUWMEeE0tSDkoO7cBYvJzyyK0Rew5u5kITtTHR6l+xi5w09RYeZeiEcli+vetPiN+DhlMfY4hVdVMKx/arhFZJ8SGcyN7AFr0UIskso3yKDZn6qnzjJ8xvwgZaMcvCNw8V+9Vwzd0zZ7NhLGRivcyTBWryDyjxkiYlnGH7LcnBjbfHSTDrU0urSc6mRi3pYYVGSAHTJaitty5gjP27SN4Mw3dkvyiZdlT1YcgWOCPfYz+i5+dqKU7pZC7aoW8Blj39mT7v6E4mnMwq4PBXCo1HXkgfNMkuxio9c6VZ4Hx6eTABataqZSDDYXsKaWuQ7o4j4DB/KP8zLOTzepsNHpGDgjTeuHFOe33g1C1WS2Z97iSZ8KMuJj+UT+ZblQsiL/Kfx6odqx3MrllvPvlMZK1xI7vzK4tn0vEGMn7Q5aiUyxU+I26fx4g2C8U8hAMTYe3dBZ2p+kfijWK7YALg5KKed1ITCLINa+cUKEKnlvbZjNuIjIqHfAaydVBj/vZjp8IOneufmrAPvumhMfU9yIKp78/l4lHfZIn/YOSSs896DJ3P433MWobxXvy7knGxo8ZmowKl8eRqu5q3JgtpvuxSfgx25R4OQDrxucv/XwEUpvpum691KM1BVorkbGsRwepYAPzuv4d6zCGmwgdlMAUbnOgKDOG2KDv64q9x4us9As6Ym6uy2GUc3+ZZU4YF1vTNRkGuU8wwc=","layer_level":2},{"id":"84f45a10-33fb-4d11-96bc-c2372db645b0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"内置度量规则","description":"built-in-metrics","prompt":"开发内置度量规则的详细文档。系统介绍27种预置检查规则,包括单表列检查(非空、唯一性、值范围等)、跨表准确性检查和自定义聚合SQL检查。详细解释每种规则的业务场景、配置参数和执行逻辑。分析ColumnNotNull等具体实现类的代码结构和关键算法。提供规则选择指南和性能优化建议。包含复杂场景下的规则组合使用示例和最佳实践。","parent_id":"706d1a2a-8449-48d8-8a21-58483495929a","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNull.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnDuplicate.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java","gmt_create":"2025-12-25T23:43:30+08:00","gmt_modified":"2025-12-26T00:54:06+08:00","raw_data":"WikiEncrypted:OuxMsU1ZR9vEtJ0zCjJ5psq39dJzDCCGZ2kMsUcZ4nHLR80dyUj9VlxSLH9TMdQ/5R7EcCGhVPV7g5jxc+slYTmqPswgnGB4+kkoQd6D2uAa3lUwH6i6SW3HMueL0z3sh1ciordwSRnNz/pzzqSDAmW36jY7ot4fWarvjhicwX0dKC1K9WXeiM6j4rMehpD9CJ3+vfycOdI082xEWJ80wYRBC+LEyUbH8O9Zr+SHAxHsAdSxeb+u84FVHqjOhWyVv3YkuwrfBKBAmaJQL16GYcR0t8Svkzb4aGTUge3++jz9D8fWXrTZZPWsSmNPjW3rk9QEcnhy6jXamEduQcqkzaZ3tyFXQkL+eOR6tZA3Bmi1lUqsv+j6krolzqnDVNMXjlkmSVrHFLoh8dB4AzwZFgB+/zsHZDLWfKt/NH3xZ3qmYD2VYqVMMsvyD4smlgj3damFixpcT5HBA+0dBfQfHwiuRj3LoObUqfAySYnjEMf1kxvDubwDilOhiv9Nb+Kud2sGe5vYYF8+iIuVHnbg+ki4CzbwxZ/dd7YPG9gqtYZLvW6Xs2QpQYUPHvK7zx4xYA94SrErg7yvei0F2Rbb4nn81PlTuo+HqSeKem+L/5SxCUps6Jx3KrUtCy+WnLp+kNrF9XKkWk4bkyIWicaSHZsxHdPU7NWYN/nbXKhZLb/kqW+tQ3nfvY53RthddteFyxOfM4l72mG2rj1zWGnIiyn1pykiYMQeG/LyRbFpSJhiDXBop6kZB3yE9RH41qGvLxmG1LbPhL8NLpkXVVoNw+xZ9aMrKryTTxO0wpi6a0iw075Lbsk0UINSTGBVBrWCnZddo1hzp9FqeNHk//KKB2m5rew8K0jjNYaCMrltLfgboq6LKlo22t5ObTTjCu0rOoxPTcOUoin1czjKtxFMETh43/R37pQxAF51kpH7gRbBx+oCPc22ZEkMtJVliRd3Vr6i5c90k8Jxd9nPqiO0LcYZ9923lrZ0u2rsMSvBnIIoEMPFB7O6dDjFC+J8tm+s3iTppxspbY++YL9UNI5DkbhT0cnP/pLx6fAj9pC7OoqmCdC21eTDMZrmidFxeY4LH7gH2N144KHG0M+2aVdc/F4t4FVxlhi7CwtEu7JgfcRUbTJeby+s+HuqiXjwe6eTu3iRGgoN8zhnTm1AY1seY21ixhAIrSfsVtvRIuQ0UDM2uVBFSXgWq20ejhSM6FlL78CC0xC41w0seFs6sLTlVX91RUvQOlmG+OELH5rZRpnEu4I8txJfbpuWEf7BzgIhxGxzqbKVjWYN/4u0tcYoI+G/6m3v//s0u8mh5tW/84noTXIK3vPtXglvwZaO/5eq/sM9cpQR5QrHZ/HZMzovefhFuNqfybMitI9MtlFj/d5uNIV5gwYI2zcHrQFh6gnQm+yPZjwBWx+Db4j7Hz0tcdC671Bb3KvXy0DBz8J1Mti9rg/Bpz+O1xibgLhP4OZEyk6SIGk2Q2gt/ZvizbV0O0gKdIrvSyAgUnZkjxdWrWux9aIZCOfiHJ6vwSwIsVo14qVM1yWBzFYBKOXOBvjSR5zGljiAHj1C4cybFS0RISOFs88Teu05wM1/tV52J27xGChpgoyTG1BRBanFn0lm6xzc54XSa016HOhdUGCc5Lg=","layer_level":2},{"id":"e9edaa94-bccc-4cd3-b9cc-e7491ceccf23","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"ZooKeeper注册中心","description":"zookeeper-registry","prompt":"开发ZooKeeper注册中心实现的详细文档。详细解释ZooKeeperRegistry类如何实现Registry接口,包括节点创建、监听器注册、会话管理和故障恢复机制。阐述ZookeeperConnectionStateListener的作用和状态处理逻辑。说明ZooKeeper作为注册中心的优势和适用场景,提供配置参数说明和性能优化建议。","parent_id":"3d9880ab-c577-445c-bb52-b4ee5d0415a0","order":1,"progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java,datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZookeeperConnectionStateListener.java","gmt_create":"2025-12-25T23:43:33+08:00","gmt_modified":"2025-12-26T00:55:06+08:00","raw_data":"WikiEncrypted:DU9QY7EXJ8zTUfNnhg9yV2m8mFS/1W6prHBM7MCKFiq5CTgeNXR2shu3U6MoB+T27Vi9Pr7ktlAd+0NrGHsKUwm1wz0ZyVMK6fMeCzURv/PRN4MB7J7trEUEUknEdDEI6VD4PyRyiooYtcJzmy/MoFyZIKFQFxftBo/ZSs+r7ivDd6H2v9yynCCBqmjDuTz9Q6aDkPxabs2dt+ZpZ2tfVn8TusDo2fPqelZ5//kQAAf+mHERL8n6ehnjQbCLX8ZVb0QXAtIxalyu+ioS+yQn7IWQGC6n280bvjHMj03m1thblOZcmOVmLnKyibp68b9g4N/t2lVmeDBn/uugZ3rBDL6oBldTD8LfIifok1lZ54OvSszAs9iMmf0+1ZBm2JFhhlmo1OPfUIWF3aDHXuo4LqBf8hox0804nfa3jXNAXaXB3p0dwhshx6L15I9dMb9CDTntktutPI3iCGdth4qW98dBWLeV1e4LEmDVjkKQVYKBkgAaAwJlHjKWAImWYcbgy7BMjDG43Z8SFEL7MCxLloy5e2fZPN+FE0LfWLNBwBGlo9NtNw+bakz8NIo1K+Rr53T7A58kUkBD8CwPDmqo+EQmLKpkKVfnfpaabMHi9R7qqaccyVKXGkBnoEcVuMLMaX5jvQ7+RWRKnWgqVdiTzBYYU0A8vbBN1iAF2ebmUcpDcQZa+cwh3jXlp+Nivs00lpNN9KhQkXqBRYrNSZlMZBtTAISo9tcY7ER6oZjbcebgISB+kYvRCHAmbt92RPSi6vyAAcruf4/59dY4XZZeyU3KkfKBeEFk3Q41L38k15ZARmB95Q8GBzd0iD3craJkCiYPMYwvW5VRCUwJdE5cDZLpqQwVYNHL27iQErBKJS0aTjhDVw950ELFvFQ5GiHtQbjoiU/OOwTnTahQa0VNdIDCxWSADl2/Btws4iSY/UjfJi3jJpLRqw3QAuFXkr0gRCjnLQDOUk/wdwN28EgkwGTxMqzFNRdQBVE/O2poxDcEViOQO81QYjhkMTmxYzPDeGEz35vvUEiL5YH/hyM53AOj2n0dbOxcrn7OtE0ff41xAXDBMTXz774awBpB6MRH6942LUUB4/X9XrC20vI0l4Fa6qNDz4W+1YQiDTv3U44=","layer_level":2},{"id":"36510586-6119-4b7f-8075-ce313c0bd508","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"钉钉通知","description":"dingtalk-notification","prompt":"创建钉钉通知插件的详细文档。解释DingTalkSlasHandlerPlugin作为SPI实现,如何处理SLA事件并触发钉钉消息。详细描述DingTalkSender的实现,包括消息格式构建、Webhook调用和响应处理。分析NotificationConfig配置实体,涵盖Webhook地址、安全验证(加签、IP白名单)等参数。提供钉钉通知的卡片消息模板设计、自定义消息内容配置和实际使用示例,以及常见问题排查指南。","parent_id":"9b0e5495-2217-4011-bc46-1d550de3afd9","order":1,"progress_status":"completed","dependent_files":"datavines-notification/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java,datavines-notification/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSender.java,datavines-notification/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/entity/NotificationConfig.java","gmt_create":"2025-12-25T23:43:41+08:00","gmt_modified":"2025-12-26T00:56:04+08:00","raw_data":"WikiEncrypted:MclloEy4bDTraaKmsUkqfI9PE35FVqqGmBXMe8l68EaW8kMHMyMO7gMHVZ7cf/lZ4t04O3JKKxrjGSTe1DzjrkhHZVuQWPK+z2BAriBJYob/qAZ+U2sbLvRcX+XmezA6YHL0wXXoS4rbC99/ZDBuOzCzeLZX6XOy2Rl9jL4mY/P1KmKxQIrBwXrq54E7g0PL55CdL1eLnPvS/WYceXPnK48cnLMfKLKkwhyFMVlG0QmphW5FCYDs5mG/Jbe1MVVOP2dmUSkfysJOzdg5sBfTF3KJF/ygfW2Pz+O02H8e8PYyfvFetoQBqt74Sg2t+FGmhVEXIS6WcC8kEuc5I0cUobivu3Iv8DZldxt9OQBWMc7lUgHKiX43TZXSYxUTX28H8Ieabz3QkWsec+H7b68TTX4zdlb9W9r6IhJMfLXEcUoKnI3ZwntNlgmBkWlOyUfZMwpFF5QdcX2pmkqeJH2GGm5I9eqPPu9/yOWjhhVzgiVercOZB9osa6+FMRo/kbHrZASDYFsoJr6TT7PTDY8CrPL/0SeRmMiZL35M+vvhBrTenvalKDd4DVxbmlwsY3AH1g38/kaqj3ATPufqVH6TQ+HW0saQEnURidHPZ28U/oRNSpM9qE+PBUDevHemlQlNw+7ZNbQ0pEel0wjKTzizrH9qfV9v0CaYpWa32+YYhnq5F6bodAbUriWt0vkS7/TX8iNQN9KVf55y/IV/drMoBOJqMKOxiSuyAdG6stY9RhpzeOTIA0aAsCn3digZXkJ7yCxEaFoeBpbyAGKKNIG1EsO3M3knXdtA0Xn+uC236elgqgM+po8/woq5RBm4DnkwJOyANK9Au+ilcAQImGfXHKJsBNSKwpERYxkSTG5i9/RSHqrPd0qRQOj5WD/xvWsgzivxUEuQcozJFihJnX7j2TzeRcxkIE1j3tlE3oJr/0c9XCHMtWh/ObehGWU3krim5B2l9URqYPTpemiFWDYDa1wB64ZtMyQqmElSKuEq9xLPLwlbhY0iOQHjP7d/HNGmnyb+IlNJmJKtLhWUiY+9907qCtXPagFRPfGu8oBB7IVZJI04wOUvUu6SDJpt3dbJyAL1zsbgyjybnZQA0n3iJ6KXJGAUZBpNzPLhAUXEhRDCXgSPt7KxDJvApfef/xNdJ2GsuGwXt7z+sgiTtLcg6qRAwcUzxHtFqoMlqJdpUNvQQVzQ1EHiTdtTW01cXze+BQ5/HEQhybIJC7+Xl/taYxBkioMhd/qKq2VkZLtFFiri1YnDm6gLZxRDKrz/PBvLQ3nQFvfSoY9LyhhTB87Ym/+MdPPR95R/DLuVKuOzbVoteLBNos9459Vd00IBRkMAju/Crfhe3n3naxAHu/6zH/HEfjCFmeii3BAYzaxt9i2LGsJoFlgX8gStDiKtuHehqNTQwQO0SW2xVGUExnr4hpfkSlkSdFpMHhLAxYX0wiYrAAYKe9inlnhLvl1BoU/F1jPJ10VXFdrSmTjzpUGB7vOWK6007SXqYmmhkBWA00w=","layer_level":2},{"id":"68f84f86-d6f2-405b-8e9f-31f0bdeec7c3","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务调度API","description":"job-scheduling-api","prompt":"创建任务调度API的详细文档,全面记录与质量检查任务调度配置相关的RESTful接口。详细描述创建、更新、启用、禁用和查询任务调度计划的API端点,包括HTTP方法、URL路径、请求参数和请求体结构。文档化调度配置的完整JSON结构,涵盖cron表达式、调度类型、启动时间、结束时间等核心字段。提供基于Quartz的cron表达式配置示例和最佳实践。解释调度状态的转换逻辑和相应的API调用方式,包括调度暂停、恢复和立即触发执行的功能。包含调度冲突检测、重叠处理等高级特性的说明,以及常见错误码和解决方案。","parent_id":"13e13644-8e2f-4f5f-aa08-89d3878d5113","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java,datavines-server/src/main/java/io/datavines/server/api/dto/job/schedule/JobScheduleCreateOrUpdate.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobVO.java","gmt_create":"2025-12-25T23:43:52+08:00","gmt_modified":"2025-12-26T00:56:24+08:00","raw_data":"WikiEncrypted:/AdRtfrNwexQ2pJED9IsQdGXyVtCR+g2NFYQ3EfCaZ1YXmUwlbE08VgEhWI4AzxkFpSNbUbGeI3odluxtVJcqRMDMP094e4kpx4mS8yQhfctPVHZoAuR0uAo1wrlooWqTcIvi1vWHVA+dfAHGfPn3bow5p8ndJO76uvnAIXppdQItyFkfoT91bsTt8VfVIJ0kE4astSxVcs9IO/dyQ9UHpgNPYav3dFp39K5IcrJSempPJemCP5D/pDAwD6ZMgxFa4wrdY3JbE5v5xN5N0b9sdwcxE6YUGiU82dpfDd0CHc7tuBeUrkkHebkzkeXRH4R8Ewci2e94AHAaiwZa2Q4RHVVrvrGOS0slCWvbZTD073gfnrEJEPxzq2A07geGLdCmaD3N8Er+xFAjNceYCagPdmn2UpCQbiX5xnfI7ghhYsV0VXeih2Zkr5vM9gnhxO8JTbtqy5MzqcpOEKEvtMfQqZS1V5ztNa7Yqvdv2gPYz8xebohUtL6FrGJeofwTgrGZqkgrU/Xyvur5Pp7A+6oX/FTma8BzV/A0Upfjg8K1vRGa5BTj3vJ6Xj6x23R4TJU9GSaGhZapZ+TFQkB8lGpYv+epn0KR4v9CohRuEFMuXo01MOfAZ9TtiQq577fgkGPkeQh9nz+NfJ80AaQLtLtElA7KeLerzN4yOvJSixnMin6czJutVnwZh218PH+FXlM5yjtaMyg7crj6xN//rsSZCwkzNph5/sp4cVuOUPvlMYR4Q4+lO/2nqw+UxZ/Bbun5nV/lMW3xdJ5cu/ElD3r2HD2uBR9F7lEi8E6aXysMiajlrrmugRenjkYZUThd2nKPoY7r6V85syQwKAgbiuNY4EqU74DvztCGUofWko7XvawLRoddpeBMUA0aTWCNbdWLXa5WER7RVSfSDs47hLwM7b/6N6uGZrUBv2eNtMrSnEynBBayCvGJLu8UWyw1QpWZ64hJemgPHzG8F/oepPtsqRwzJAUnlVIP3del33eaOr6oUI1VDIUkNVFmtaZiyRbBjr1urMSES38axpxthGT9HYH8Ce5F6JutiskPNN3DR+6EI2Ov3uFqrOjWdlXL0I4otSNT3b0jlcNPRpX1oi1677DqjwSrqVR36ZpI6ZG8ak0xgqjUa9jkCKEOed3TWHtKz+DyDyBCuUkl/BB0laygvvdEpEY/n60WLgTDGxDIB6I0maxpsR5XTBoRzYDj8v7/dIklNfhU+FO3KegnFcPKf6DVMDfgs3tdBldcJd+B/yDIjnmIcgwKSr45QcqXipAE9GoTm3L+Govji7K2UNtn5zLsdnGMgMWW357c5mkOPVGz6lLKgMn17QcKDa0X7VFFaYcc5Zk89cyQR9nr/8vrOp03Mr6QWHdNH7C8qFFNY4Pe5kbM4kEsKUQklkVOMffxP64ZUFpsLR7/I4GlUevWH8glsV0xVHzmPlcg2N6yknmDPR7GsJpm9Rl1L1v4MtdmBg9Vigg2yZ6OXV4L4jTsRlZGoSDp8uodSnXd8+iM6vmf/4FN0ArE1gk0Uc/09kqVMbU0fEBzbbyQ9HT+ARYCNHp8lCt89gBHyn7TMf1RMAjXtbVeSQfejO5Q+yL/avU","layer_level":2},{"id":"21179d81-91c3-4822-bf9b-316332af72db","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"核心页面功能","description":"ui-pages","prompt":"详细文档化datavines-ui的核心功能页面。包括首页(数据源概览)、任务管理(创建、编辑、执行监控)、告警管理(SLA配置、通知设置)和用户管理(工作空间、权限控制)等主要页面。描述每个页面的布局结构、功能模块和用户交互流程。分析页面间导航逻辑和数据传递机制。提供页面开发的最佳实践和常见问题解决方案。","parent_id":"f6fd9d61-f5fe-4cee-a269-b29ba2583618","order":1,"progress_status":"completed","dependent_files":"datavines-ui/src/view/Main/Home/index.tsx,datavines-ui/src/view/Main/HomeDetail/index.tsx,datavines-ui/src/view/Main/Jobs/index.tsx,datavines-ui/src/view/Main/Warning/index.tsx,datavines-ui/src/view/Main/UserManage/index.tsx","gmt_create":"2025-12-25T23:43:54+08:00","gmt_modified":"2025-12-26T00:56:55+08:00","raw_data":"WikiEncrypted:ursHfLzedg6Fx4QGeotgG+cRKFB0LOe6M++SNxDfiy77xQO6jEPHLNk7bluCyJ6VIIhc8ohvhcoO1bmuvu/vQx7DlUkdUkRT6Bg6r7s4R9idm66YBaYbS3sZGnDEzSZbz5iUv+NvFIPUcxZAdgIdmUnlda3R+N2f07+MuHG6PK3/+JGP8027lNk7gr0qjDcm/LOzKO4ZUj+fOxzwo388IbC3IEdZS3rN7fKruijR3nblstuLfI7qex5L9ck9RpQv0jW54durJkgu1K000ElJG8qDEGzFSF9YgM+rWfI/UL1/LzQ/5gKGVlJWWqbb6h6v8lA7oDmldgdnPZiAlOLMNZ9KZHL+u5yUa9F8vADtyJRtEwP41e0cWKkSGZlHutmmC1A3/5fLPB4mIuy7J0i2brC4mZ5cFWV5GCQ8peySgZM8bEe+ObmK0PSG6UKcGFKhvat9YFl2+GurVkhrjG4RtdC3MckS3xUxSxehte90+W0C7N5b1ud0wcR4WJ4xbODkFzGJ6nAt6u3QWI8xrkinz+kv5kXO7s9/MgSg2qxGEixRwwivZB/gIt7XxPK0Z9/SPAkzkCTY66J4kynwQ8vSZ6SKFf+5jGx8n0fZvOiiT6eQuNA1Mt3vcNPYtCLbZ0ibQ3ogPUMWawkIJBIjRjW1gHrLs55koPk120fAO8Y90I3V8tV5WskJvUcF0NWzUnHhUrHqvbkfs+5W93PQjGFKDNwblKkp/T0p+5N5aVa9NBQa5hwscMFHpWH5QkpyyJqXt9ZiSxivRLAOa6t+1be/4R02Q0hWY3fYG5r5FYtmNOpRWcoLOG8nGZjYIIHsjFshVFaHwoeXtDYYVMmpb6FRcQd+/eNsvmGRydNhn15HCoKkEGego0oCdnSY8EIdmWI+nFvfMF2SpejS8mZ4Zt6nUT2J0jT+cCZkLm1vFe0ry8u8J4HKps5GL1h6W5c9t+4oe8ENWArqXEAMpfO7INSub7J5R0ScwHWn5FCxRMZgrrWT7+5eYkBNIlMtzzn9LcpLuFgy9vyqMPurjlod/FNXLIvcDlsDHUonwEJi9uA4mYRbROKzkMYIvruwzD8rgo1GJYcK8kNaog6aB60004hdtvwMEl4yn3GzzPXjzRu/NLw7UCcKcsDuqCLvi3rw27erHkzkGPaBz78dWgsKqxlMng==","layer_level":2},{"id":"6ce0e176-a6ce-4f78-8d38-8e1aa881f109","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务表 (job)","description":"job-table","prompt":"详细文档化job表的结构。提供完整的字段列表,包括id、name、workspace_id、datasource_id、metric_type、config、status等字段的数据类型和说明。解释每个字段的业务含义,如metric_type字段表示任务类型(单表检查、跨表检查等),config字段以JSON格式存储任务的详细配置。说明表的设计考虑,如使用状态字段管理任务生命周期,使用工作空间ID实现多租户隔离。文档化该表与其他表(如job_execution、user)的关系。","parent_id":"3c7fa525-a12b-4451-8146-b1bcfafe2f1e","order":1,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java","gmt_create":"2025-12-25T23:43:58+08:00","gmt_modified":"2025-12-26T00:58:35+08:00","raw_data":"WikiEncrypted:+/ClI/aSnqGSPl1mLi0MwERd13pQNt6YLu/7fbItWlGq1NhIMLzq19iu2a5vF+fFWVDRx8592iNVAmVAcfIz44h+YUte0cWT0iVPzeL0K8wb6jP0819ah9j8+g5spwQlTFaYsN0yyUxOivr2ZReL+GWwGeMT1M1/yjK6e89riDQBY/1f1NSdPkfDAiTrGujdB/8p+wISlxgmMe0mS8tHzi6mzeNsmCU4DPjCt606fUNOeOxa42WReN+wd6YtDvgA9/tocXHvrZ+w3oFd3Vy06Dv2BOKTPWEkDauZOUidiWXb0y7W8H6diYMJrjN8jPNMLoVNZ3fzwmG+FyKhhJXebkfcHyW0QFcg1POqvLOQaVn5tIgSxTCp6d7xX9/e04gmPPCYMln6eqAFmGHrUwT1/Iounq+c8rC4Uz5mw8/iFiS7KEODJqBymAP6THRhI5C4aG3oIt1/jD1rTxO5giwedUllzge9v3tUbkpWOQ/H8BjY3HPsM8UE9tOmOzqHiwPgU7xRdou72++wpCTu2RMNb0mIiAimaPeX3pwGv/dnJvg8sf3PIzCxS901DleQKvNCFrG/FQEjMddECnGii2QDogFOdEVsvWmaE3ZZIRwuWrAmKDYJG3c2YfPMy7GAtwtRr93res5BB3d+aUsVRqTR7JrXhfZbXQr1z0jASS8SJnG1KZIJpzw+WIhnth2kvtoMfzFSufj86V6kPl7hCY5odeGubYhEFtY+SGFwc7QzPnZsGWYr3qhjeeBkaI6tnmJ1oZLUQn5L+eygqRCnxErSkdXuZHSUvKXy2dUwKMTup8zLTXFeqCktAOYK893NcsFhjeHKfhxNY4GVnxZAuu8uGDtjX5hNsz07puj3F+UlEC1uWplWW+keLDywhe90EGizbW/oe1QBccIHy0NgdIUzlVGC09nblSrvS8qeMsW+uN2/bMYCO512hvNLRtDv1PBDOxaDgZ/gLZSGQp+xXs+4vb79KbkRvlHcUaLp2YIs89wl0fVXYcuoyIWzHbOXwoDMGlQVX8rjF3rsdmIxRY8SqxA4s+CTHNp9tN5W6y6lkMtTZYJSw44aGwDtgTOjKKTVQc/4gub/bBY52+ZjXv5XRz4UlqTIxIRySUD+rtrPklK+tWy6dA5J40E+gn/SyZwA","layer_level":2},{"id":"24247a11-9e9d-4d52-8825-9a647827b4d0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"实体实例","description":"entity-instance","prompt":"开发实体实例管理文档,详细解释CatalogEntityInstance实体的结构和字段含义,包括实例名称、关联定义、属性值等。说明如何创建和管理具体的实体实例,提供API调用示例。阐述实例与定义之间的关系模型和引用机制。描述实例数据的验证和清洗流程。解释实例的生命周期管理,包括状态变更、归档和删除策略。提供批量操作和数据导入导出功能的使用指南。解决常见问题,如实例数据不一致、关联丢失等。","parent_id":"493d76ff-0c76-4864-9a2e-0a1aad23f133","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityInstanceServiceImpl.java,datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java","gmt_create":"2025-12-25T23:44:08+08:00","gmt_modified":"2025-12-26T01:49:57+08:00","raw_data":"WikiEncrypted:WnER6MhWFG6N6U3R1m3zi1svTCwptoJfG5w2k9E6SHgdnnIN4LXuOCWHjomPmwqNy3OiafkZSljo9IEJRxgbJUdS+2np+NSnzmYF39ksiDKM9YluB4skeFKFgyBujvlrVmI3XR1lP2DWi8Yp1BjXJE1Ay6PxMpNDfBICIiFeW+FgSyoDtwlIGRqTD7Z3uLFGU/q8uj0iBK2EsZ2NCSbr9m4PW0A6nDSQPElI/JIVkdbsw5XFFUJKdca0zHs6Ip/TAhSAiCvwK/GIXlibLcQk6E5BjBaJ343OEdXHR/7Gp/qmIhy/+0KIIf2xvUGdoGgzfYOzux22cjzbdAhbqeKtYAGFvq+oZnebySpMzKXRIFcU2obXBKx6AbA4++K+9Y9mL8ywYqUDSajI5BFVkf94YdlxkwvczpJsW6drMu9WRy5HSAV9UchbNFgj7MhCAhPVeqyweHc7NmamlIEUDmTVEy2cyFfu9nGSoWKJt25byd92INMgMFVvcKPGylPtcy12/AK1YQwlR7/qn6SxeUbgPCp+FoNQhJ1lRR9R9E6fxQQYYEDpqZ1kV64khNkhv6anumvNqXj9VFlcMhKUNNr+IGO7JLDs07fovWzuLs1Ntkmxe+U6ch66Nm5KlFY4Mr2xg1PXZZeNrMWS76SwWF4CrWPZ++afKG1+komxIHz4Q2Ptv2V2BxHPrLnHl8Q0GvtsU3DoknSpvKP8icUkCvsWsOys0h2uY9ROUFFCA1q2FIANYLjoWKpsYXWb9Vr9HtK3TCkMFjitn7AXzTPzNC2TlJuGwWP2jU+U18oMkQTPtYRgs2cyx/utK+891sQaNQXh+IjyEoyG5oSzxpgRhq97HBqZGJuvXioEdOEIDmXACC3tpjx18wXbcgkuXjVMqEAQhGv2qyGS54VxqS9wScGhcZItmCvS79BGawvtlnCFnw14MrCZY3UiKtAeSW0iKHQFBv5cvdcMo9KMIx1zSLQjIS8//geBEJCRyzQcSRGslMq3cjbG14gdd0LFIiC9Q4qdAb8gqmE1JHExcXMOSA4aTz5qUzBF8TonWEEy9K4xdz6B2ZWSet9DAmdaBaEGX6krC1ZN2SXLR3dtTpYhZ/hVXHIinq+AemOmkgMlJzWyxS6bZx0hPs6s87G6BVpTniynyTHcEHMLJ51qXT9lX08HY/5OGhdJiszvAja9ypkuFsGArdOGlLerM6RfAdylgl0rlsH3czk+kkru4bgfeRF2+n2MoCK9AJaaSn7vbJtGTCSc2+Vyx/NGdSK5v2p+GFP/akhs3rXBjWvXvegUB1UxfzOZ6MUDb4DJGwYkbO3hHwmfmIDoNz+eWd7qUJXDFXTMIU76KWZSp8JQJvOI0gUgBy0HoNEYGUj0QVZn7F5szl2rb4+2rPJtON+tq7yDN/uYlHsWyc53dZpaeL9ROFbkQmTDxC0A5NoF+YrYWwORCOU=","layer_level":3},{"id":"802ef802-00bf-4a33-b9f3-157d415741e7","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"变更通知","description":"change-notification","prompt":"开发变更通知功能文档,详细说明DataVines中变更通知系统的配置和使用方法。描述如何基于CatalogSchemaChange实体触发通知事件,支持邮件、钉钉、飞书、企业微信等多种通知渠道的配置方式。阐述通知模板的自定义方法,包括变量替换和格式化选项。说明通知策略的配置,如立即通知、汇总通知等不同模式。提供通知状态跟踪和重试机制的说明。解决常见问题,如通知延迟、消息丢失等。","parent_id":"586fb977-73cd-4d21-81a4-ecfb619947f0","order":1,"progress_status":"completed","dependent_files":"datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java,datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java","gmt_create":"2025-12-25T23:44:09+08:00","gmt_modified":"2025-12-26T01:50:33+08:00","raw_data":"WikiEncrypted:MTGOV8yMPpR4TI1lgrJ8xIYaKcE+7ghMWNQsrs2/0sChNo+B0Ne0pi959D8Qb5ath5CKp2EK+cqPcp7iTioSrfn8mZmTPRCNpHxpZGHJx/+CvvaEOu9NHdcZyzu2nJfVEyp+IxnyDOlD9xEZCnTCc+j7RG4ApdtlPQbWlP5eueMpQ5EAyJUdUPQqIUH6erCNUHgKGpGylcBzmTXH9TFMO/dq9QEm4VP06A4atGOxqy3B+O8fuG8b8wAwrboqnNen/GzAqIppKopJdvwirPnKXwwEzWqunei/amxY9LSKqeWEy89Gru9bkhYeqY8wv5gZ2Whow9rBow7DCcs0OLFFq3yTgXvDk0UACLczUEY+BpuMZ8rTNxP38jfcsIE0wDnopk+DGxiCb+nLmxscmS38AswxNddHXvMWoa5MpRpeSHX6mB5HgxI+7HF18f6kyYRIOAIpfONe4GF+yqU0DkPWp9Pk2G4ois6qYZtAV6xAoNqGJ6he+2aWpQM/DjjcEIWwo3oYjvOH9GrtqBWJj+cc/xUQyqX4jMn98tn4Zp/hdM97RZC+U/gYYcH9vyH6wMF1H/MeCzDo02zj48uW9F/tW/0vo7cRqR3JlRYkfoKWCz3DhR8irgYjjIWrW51vH+ngbrL1uQG3Yy+TcLiQW88rV+3YyHNKjQxa0bKNyCd6x27NPf+NKdy0R/WyQB5Usf1hj4WqwhQFygHmiX3E2myrQ8w3zjMkHSrB0a77Eetb0yujq7r9VtvsyPVps1pbEIFLx2MRXU9aL3jRlJyvu92SF4U3bjdNefvv/nraQXkDL+Ag8z/UTgg5hzilMB+lmyzHYaQWWrpqjN2Tk0X0R7Yf0HXgkUl28ixD/cCHsVp3Vb2YT3zIz/9k9aCRpy74SJkXDe+tckNXhIFVRqCSVcScnglNFJrud3xSS65l1P7TOAiaUoujIA0hza4eeGCnSx10Zop0OrzPaEvk1wXOmnSoWMXP5B1KtLO/V88xCJAxljZNctWd6FMVEr7CNnLGno8MRg7PPlwuNUxxWU6WrgUjayALms7shhSwhHzmNRIVl1s0R/E4mPa+lX/E73yCa+9OhdnojBvCxIYEzfgJKA5kvtfHzoR+5TrAw/OLrO4JkIACsB3vJEq9awmRoifqJuo91ApILpPe/W89jlVkZPSwI4vtKyc8bo+4EwapWHhOgZqGxTri2vjqp6aY5Kmt/2rP25PwZJeF/QmPQIi7DhzhxJmdGF8h8H2O2JzpBMQ0vOi8yBLkxmA1kcpYbgdb1ww0SZAHqGpNShpgestpj3VxuZHg+HN3e2iUeXmq/Ns52q8XCqfUJEu/6W8GYOQ0JNh8","layer_level":3},{"id":"e52eb8d2-6c53-481b-a2f0-3cdb7d254a92","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"安全配置","description":"server-security-configuration","prompt":"创建DataVines服务器安全配置文档,详细说明系统的安全机制。包括JWT认证配置(token有效期、密钥等)、验证码配置(kaptcha)、接口权限控制(@AuthIgnore、@CheckTokenExist注解的使用)。解释如何配置安全策略,保护API接口,防止未授权访问。提供安全配置的最佳实践,特别是在生产环境下的安全加固建议,如HTTPS配置、敏感信息加密等。","parent_id":"d6d39194-b46b-450a-9e23-15374a060630","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/resources/application.yaml,datavines-server/src/main/java/io/datavines/server/config/KaptchaConfig.java,datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java,datavines-server/src/main/java/io/datavines/server/api/annotation/CheckTokenExist.java","gmt_create":"2025-12-25T23:44:13+08:00","gmt_modified":"2025-12-26T00:58:06+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjL1I/FG7PmqS62tiq8EVEHuciShdv1k5yrDUrm+5nz+nrgyJa7cvT31ItXsO/9cTmIRy2o3+QzTZiW8JjCcXKf7fcbCcwu8GcJm1K4t2LhyyzAnraSWSmmG10u6egY/825e0e0MgfZHRQzTEDISdgwFjLNImZq0dG4LEDF76lqSzyYWtqvofzS+x1aibA1bayc+gIwiul4asn/9bQFxt6ps41YpWCYvPi3EhkvrZ3kbuB9XMYD8tZTbgK2LoKaXvsDaciwcH1wqrUUl6u1naGl9nUaWxX2O5vp+AB+MQhmRZOTpyIk76LpzB36MNfMPiXpjqByRmJBZCht2kArgHeiBfApSGd1y2RJ9ZcKLjduZyqC7aInLPozHwes3dpSIVMXsesjvBsw8XfC0MAzxeyNUi1J8fEkAiHzAIT+WoAecIse1MgFF3LrF6cEjCDqYZ6sYRAnMMf0wy2NhcCR/1xbSScUVMIK51OLa0XPlMt60wenpr1XjRejE7rlU206lF/us3HFg5c1wT6spXciPkUYE8sgZ1VRYpjDUISPFA0J2n/g/2nnUEsRpU449I/rVScffpzVtHnZPIsqvFncK+tz2jWWL4KlSXyQMBpNclIiYRhs+FvkEzol6PQ+w/EBmajFH4AIUlJTnKH/aJAHMEQweS8BHSL9F4uewOaQcsiFPSfBWWjPlAm3wvDmcyjqCCR9/r2MGzFuBycryAgFOLXVSL6Vy4wWFOPUxecS9PE/EGYiin9xa1r13sGN4a1cXzxwmgMPPq8ODdJ6JeKnf82S6CUsORweVVGTOn0RRoYl7Bcj1zavk5tbUbkS1RZVxTbTKFGG8DnZnVDFT0iTC+GrajoI8VRP63B/v99T+tZFvcCNOiHepLDFaEU5MIvYg5QO7/GW50/uRNIxqUUdyT+KH26Al2yc+WVrSNaOeVtFeUjGMl71RS0dX55EWFKdwB3LJIYyhEPguBZbhb5Zl1trTMftVLkhsSRJPTryF9LBq+/giYUw6FEKQT0g0iGySfcBGXPMWFxmBjmUrxc8xbq53AKgKubJ3pHWu6AJ7FAlG6XTu7ntrWekpgLQiMSYxgCf+9bwgfuT09wxPCzW1atWfrkyOkE9ewi2gmaATonS1Vmvz7cw5305QaBzDjot/aUwN+JvWEluPl2TOBZLRzUZuu88oFWH7pf9Iyuvqz7Rf9J1s+tBtNvD3XmlCgX6eBuO1QNejoYnGLJO2YT4KIgyElrUlLF+13xVZ+msGHXWz3ZUtoRfNpqG2/d649z8Wl0xtYScCZkmXcsw23D0C/WtbIL6w7ADYkX55IfRSTi1vkmoKykShVwZwTD1HsbzjCngEgrI9lI9H/w3Zca9dMkqI=","layer_level":2},{"id":"edf6a573-17c8-4a23-a325-6f396083b131","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据库性能调优","description":"database-performance-tuning","prompt":"开发数据库性能调优文档,深入探讨DataVines的数据库性能优化策略。涵盖索引优化建议,包括哪些字段需要索引、复合索引设计等。提供查询优化技巧,如避免全表扫描、合理使用分页等。解释缓存策略及其配置方法。分析数据库连接池调优参数对性能的影响。包含性能监控指标和基准测试方法,以及常见性能瓶颈的解决方案。","parent_id":"74203214-3316-43ce-b2bb-545d7e140a7e","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/resources/application.yaml,scripts/sql/datavines-mysql.sql,datavines-common/src/main/java/io/datavines/common/datasource/jdbc/utils/SqlUtils.java","gmt_create":"2025-12-25T23:44:21+08:00","gmt_modified":"2025-12-26T00:58:21+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkFINBSOKEigsJGrSepQrHfhGRfQxS2dDVu2chnHf73O8itnBmjf7zEZt8ABtJP4Qf2ecKFWd9ZgWgVwJrHx+mowU0LwgzK6x0NYXNBF9hlmz7QPdZAb/l3EJiZ1xHDC5OIW/TJv+uqyuTbDe5DixmDyhnKEXtUjMbNrHATrmbvDuKRr+kTESGCypO2WT9iVTNiP5f+Ky8Hjih+Mvbd/q0i2S4FHAJ9CPz2dfz0RQVHS2czriU9ohEkyV04ZORlvnNS2jGzlw5ndXfksefzaxH/zJIV9OhUoaLJGVzQh4eMnqS5OzeBZgW2W/bfhCBmHkztxUvT7zx5wEjBcmQyHRtqH1QVR8LmjIEaSVmJxJQieZNROmu2LLdOyY5k9HT2X2dZR1iYSHnwDDCpJOarmDMycp/fUw9Xb0Q7udVL3lcgJZWixD9xiKHNsH0ohtv/s0jWhTodYGM+QvLD2yIGHVbgNAKWtcDIFmHf4i46IWSUqXQqa31/kKFRWdvoaMiBII7LXTNEmQdrJETZ99UKx5fi10/m9xn1sd3XJeVTEFNgBSNz06zdUEcl9XwXoVijBr3jp/BZvrSQ052wblT3nHYLdzAWbBdza4kGmQu4tsOW2toajK+T2u3KUI7ciAEbobUBLQZq33v6EfJDEkasNZmpT1tREMmUfacc+G8KCNEb8R12uYmwfm/LG6p3juOqgf5bMswfNwFZrq7v4aVcZn6ZQvfI1XbHZEEYkeFzkrCLxqqiVv9PuxODiVDSHN4oAD29VZiEs48cb5J0GmV13JvW5Sw2BAUJbZc4SOuSA51SAR/I9C0BbvFAuIh7YQYpSBNKMDqJsvR5x0wqmwW/cKEPac3htBmQTr+Dfy5s/+4TwLNvqBFcQ90oahEbhBvn4RxbcsY/VBx3SDK3Ua2AzzLpfKHQc1pr5B8UKAHIq+ylwLaRotj61HEseKnwTOt9ESRth7HIpJVh9IqfRt3+yDhGwsVqHFYw43jQZwc0+bS5ECt6eFytat2pJAPxZdyKkVOMIIAxv9RPmcCnAXHm07pLBjon1tdZv9/7+BURuiqy5Ynsnm/tF5Ct5OUyOc1NQj1zeT+348cXa7+5bKJzgr4xamfQ8HVUx6qdegcCe5fMQxs6aKrYDRp2ZyEcDb/RlDTvGMo8U5anf2UtEq1BbKL7H8EqeBbagFFZx9pVM9qqHi","layer_level":2},{"id":"0af499dc-42d0-47d8-a341-f39d5a121c87","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"邮件配置","description":"email-configuration","prompt":"创建邮件通知配置文档,详细说明如何在DataVines中配置邮件通知渠道。包括SMTP服务器设置、发件人账户认证(用户名/密码、OAuth2)、SSL/TLS加密配置、邮件模板定制、收件人列表管理。提供邮件通知的测试方法和常见问题解决方案。解释EmailSlasHandlerPlugin的实现原理,以及如何通过配置文件或API方式管理邮件通知策略。","parent_id":"8938d0ac-a871-4818-9b4d-dcba6e588233","order":1,"progress_status":"completed","dependent_files":"datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java,datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java,datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/entity/NotificationConfig.java","gmt_create":"2025-12-25T23:44:31+08:00","gmt_modified":"2025-12-26T00:59:59+08:00","raw_data":"WikiEncrypted:/tgmwByRb9hMFGCVx/eV9yfqfoK7cxPD99BvYykoIMTEuIY5d13KnVU7cGzf5tJ0zWSeKjiXvb3yVGkfKDJqQWWdHuXiWLCCn3UUqEMU5PKOEqh+n66xSKKubStV1paTueQLizbWwr+m8iEOofPflUDVFSfa2YvYIFVzkAc5e2RQ8TnEM9gyD7loWt1VZTbV04Ti9+tHAj+7b2AGvPEsS9zTiZZ+mF0g/E4idrk7F2CLwChqd7CogepqfDeTXPf1M22HWjNFNvzK1BFSIkmTFlo6dE60i+hMi8fZSrtcklYc3z59H86o7VOBKejxr30rCVvPKi5w+kXfxQ8nTrnuDtb/YsxdjMfCXPDXpgRRhvjWjvRC35jkEguzrB5fsgf2/ClmMY2yg26LjQiIDrEWAVyznNneLq1E5WPD5mip3PNDmiqdBnn31C4PgY+mBCKHTdlwFnPG9DWpA41hwLRlw3YqIlTcnwvQBdPfHyUncJsZK2LVzXri+bZkaMEfBb7NyNGFDWqhdVb1F1hSg3dEcLCeHxNwX9gMvHG11g9GV3BrtC8OsiDf9nO6yRbtc9oiKGMCfardIW6YAoj3ip2CVxx45xRILcMbtetcLlW9XlAtedjxCpjRZd8O2IQe+csajWU463T9HnGIAjZE+dBfhH/TO4c/SFZ1ORIumzL3j1yPviwvk2yEwD8HPlSPgmiC6SE5H6+My+oaarVWyMlxiO/A5nEldvFfxCzD/Bkzawt1+gPga3iz/U1zk3CBIqG0w749ibUG1grR0NEwDzaY4omo24SdrwKsqsZoAPMOd6Yj4KLcLBJedHtCeI2hnq6lKlXAYrSlNXIgDhR7CZEq2q2ZgxfCvCR1zp+HtswpmCAmOJU41vqG1dvErX56VZv3+rgePtRts7Sw4GRtOpFbk5Y5lvaVpgAjaEVMNNciRJQoQhzrSeodQ27rccqCRdNBW13L+Gh7ol6TZDweEZS558W+7xUiGEW7ckPLQJbEe+s4kXWbEjkseQL6gNRsxu0eKLKFBLzbA/xARddBk/aTRQG5U+1TIeB+CoRCaFvaPe2lTjP7ViIeWW4pgS38YrNP34EowZ/X9XZncofyNyf/ZB2U9sS9VOaG8sNmftqDhiL+q7n7KBLqID2Tlq+rqESmtXs0mPplM2P+4tAvMqff2yz2YA7G6kraOTSKlzGSG7xPoObvX0uGiKlAtXAtXFVavS/3v7n39O4jbSLBCtQ5ImEMws4xjD5KJ5IzH6vtazRYnZwhFDrc7t1/kbACWE8LM9E9NV62RfeOOPirw8Vc60P6GpZiYWzsosZz1X0AebeYXE0C4LVjlatD0JGtdb0tyqG+HJyAZDNZmj0Ri3IhMjjUVicAmQi6ZfbGreJa3UmOB2+YSO0NhVzBm/SdhaJV+MRwrWJyXcVlLdXUPo9h4RAI/IxxSWQwnvGELdIhVBEVQiUY+ydJgGV7y/ny4oRv","layer_level":2},{"id":"7bd8d8bf-316b-4e5a-a32f-786067c2d1ba","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Spark执行配置","description":"spark-configuration","prompt":"开发Spark执行配置文档,详细说明DataVines通过Spark执行引擎的配置方法。包括Spark配置构建器(BaseSparkConfigurationBuilder)的工作原理,Spark参数设置,以及如何通过Livy或直接提交模式执行Spark任务。解释SparkEngineExecutor和LivyEngineExecutor的配置差异,涵盖Spark版本兼容性、资源分配、队列配置、JAR包管理等。提供Spark执行模式的性能优化建议和故障排查指南。","parent_id":"69630b5e-3d0e-49f6-884e-8e9fe153a0ff","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/BaseSparkConfigurationBuilder.java,datavines-engine/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/SparkSingleTableMetricBuilder.java,datavines-engine/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java,datavines-engine/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java","gmt_create":"2025-12-25T23:44:33+08:00","gmt_modified":"2025-12-26T01:01:02+08:00","raw_data":"WikiEncrypted:M+m5dxh8XuRtgpG2DvE8kumjfswwXL/Jfz4NfbqIEwrbAuFdyeaUT7ZI3VNMv+eawnVUYNPIDWLGs8RVCHURA06qllQul6ltT2M0QgPe5t5HxyYcVTHQ+d8Y/zax5AcDABlanzYddjP+KY//KxTyPd+XDPhrihqDlwqtq4xJadCmgFS3xSf5vyvNHLpI0ZV+8aHObgl5XLa1AZpVDUkr43aJohYXN4aW0702fyVisssne7my8XORe9hivnv3ImSHl2lrdwn6J1I5mGHhvZrdbWYQRuRU6aoeqA+gREXS5dksTOgFv5aai+8ZLWA4H7JbM3jOOY3rWz/1WblLUHKT/uDVBBsnq03Kzt1/y+vY+X3hBgzqyFBOcC6uiVKMqN/dnIdNZGD4dRigyKd06Hwsksi5JtCW1BnO3I3biHrkHeLQq3kaLpZiYMhoH+FGvjA+aLpRwJzPWjBM/b7b1jz6GrfJBVzkEDbpayrISslvMQrsEuMz3SGBMGnGGm7ArVgno9Ud14WH/g755xJNBCVDui6bZzQvSQ2aU46bUPEUsheFjIYeABUrR00Hafq+upXqqf8ARiSaMMVsOhLT6uQeyWObZvFFuLa5my39nVc0Rpq45wCRubO9B1NpdAycmOHeV7N1pStdDmjSr7fydjdBiTGHraMO65X0UMLdVVeEqhvYCX/GJ+gXeqQGi2QSO0vEM4c6z+R4cz5Y3PabwLEHQsRq+OY23yCb9u4kG2mCCQh2gjwJbCwjn2Th1PSgqYIhDrmGUhJSlFNStXJvaxXjmIFBeB6Z+PT+DJDf3JWBgD0/E84kxsfJhwxOpkG/Gb2cgB7udLW7i1HUjSSfsc9aetrZArtReqesQlLqnw8U3cUu37lzXkBHTxlcj2HHMoBCNPLltxARivyOd0aRugAWft6Hxivx2F4B1J6IrVKFnhPW/wHtJjlWdap4+a/KMUV+bz3uSomRrbzw9ikoDcKJ4L6aZ89qv4PHck7x2vZk7LBwUt3Uc7Tums/A38lJRFJMFfR6LknHMpD7+R9GHQfVVIrdHwpzgnyZrs13+pwjEZS+jnheBsVdI6BrhSNiNpWSkzXvwMxmcPfOW9Jz9y40NfJLoTENoAy9z57Fr2aQwAHUgynoX6u+ChIk9/nwEICzNR4R8/rN5/yP9DI4BO13IlERV1tUjBH19eq+Hc7MCvuskqC7v9UKS9aBsIg8sf8FKdgzNVAMM4qJwy0LLtrGxDh3Ik7B51yZlQeJZxwXQTMM0C8LFA0PGsfI751n5UvQv+hY7y5kK5fWacwWfqabt25rhxv7k3Q0GkKVI5VCw2hIPDhyyFQBYaKIIZ1VhxgDax4hKovAUfOD8GUFfj6rc1ILYcC+RWE9eh22T+y93vMrEvmDWgOt9L75KbcEfiT7fWV2mDfWlpp6slPDcAULjUR09ytsV/JFD4Vnkivs1ohaJOzG+D/wyT0rgjMtFzUbgcvcrsueLZ0hTljYn+Iym7VMNI5bcDAIO3+T/T/zZlml+eH3ipcXrzXNWl4SxsmLKexnE0OsLAm3A9tvlNuPdqDmddiTDpLuLI8llaN1zJBSF02nNA1WKMhwyGKJin6nVJwqIf7fcF8RG8FlSUwlq/Bgx9DJB4NB33WJ3ncAbUGVu6HRbyThnkCr8RXy/+5o","layer_level":2},{"id":"860d9985-eb7d-432e-a1d2-69e59ae12cef","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"大数据平台配置","description":"big-data-configuration","prompt":"创建大数据平台连接器配置文档,详细说明Hive、Spark、Flink、Trino、Presto等大数据平台的配置方法。包括连接参数、认证方式(如Kerberos、LDAP)、Hive Metastore配置、执行引擎配置等。解释如何配置高可用性、负载均衡等高级选项。提供性能调优建议,如并行度设置、资源分配、数据本地性优化等。说明如何测试大数据平台连接器的连通性和性能。","parent_id":"3268b632-dada-4561-a9f6-4ae317e64f29","order":1,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java,datavines-connector/datavines-connector-spark/src/main/java/io/datavines/connector/plugin/SparkConnectorFactory.java,datavines-connector/datavines-connector-flink/src/main/java/io/datavines/connector/plugin/FlinkConnectorFactory.java,datavines-connector/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoConnector.java,datavines-connector/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java","gmt_create":"2025-12-25T23:44:33+08:00","gmt_modified":"2025-12-26T01:00:10+08:00","raw_data":"WikiEncrypted:o6GGI/vZLHjO8V0YeFRVo1sw1qV9mo1FndLE8wdNFald0yYC1pSCeXFzUmYlR8gWu11aL7eUDYYcTRP/kG2DwaTKdVg47SOQ8YEncyebVz2+7GI87t1L55tiYIMTzuMJfJl3BgMtpewNLsqbXHxIZ05Ws4snfXdMGmtECjgEmLNM6I5dg8emthUSjYQxXNLe3ljFGM1DFvydj1PL3RYEQmzbx1iV5Tb/QaLILNyFjFmxib/mPV6ZwYhyoQHStFW3YfRHPhdtk6RWI5SUJMWWdgEorfnzxTj/w0XGQqVbU/xVSzYgbBP2xZx4fDIobC5AXU7MiyCYGglNCmeUTwvfbZ5HPt8Ls+oUo7j+ytpxY31c2hDfzrq+l8WbJLKS4yN0f5Hkzl5E0sK+mbJ/GtjMSk2dQBkT3dRNoWt4cJk6mzehxs1ZqfO8w8VWxDm0L/H/NShhZDui4RlkNPdX7N4UU+UeAtKLWAe2lpwk8m1JsfVMcPANPCdWDQ7oDh80owvSkiK2r3mznHniaJUm3qius/oduPjqPhZAauZq2mljABSXE/GIIxBC/jv0JnmgCh1acp1iQcYKSuNLGgaQN9FcJ0VdIluqBI4exdTSztuqLuTB+q+ckTpBrKLqOBIZSvM8pTTNzUOGEniE4kdjBAb/XmhC9529v09dxCxsr5Sp3hfNFziQAYBAxJM7PB7rJdoIjKRnIabIy67jlp5JKwv1F3DywZIUGQquj2L2RMQkgW/aYyamQFNMXaVbP7DqeSbo1+H65+Bmxk5Jj+/Hsqb2qKlmXgoQ0HGt6WBqfGWWQz2m8gnpIQ9Kw3h+xAl6UQkA4R6pyJsCi5CLB0LTyLg8Iw7z/mKg1opZ2aJej3w+mr9oGUvNngfI2jP1NRFnkUl9871INQZ8uvf3icjMC/d8HZZtrBvoXMHXcl3stjxWp8Z/oumwBvF6DdhQsUGF+V1zYFJ1ConxxvlLk4Ky8pE+0GeR8L52eVVFHLHs5qL/biQLIzX9q/EcPv1naSXFkceLSyBDHc2r2aCqJBIhR1eIrHHw+hQ8UUE7tTPaxmRydYGIylDj61NiNaOBvWEKXTSqlUlu7vcQ/ZIvycNESvKO+t2COpH3QlCH8F9q9kAnTouXKNJBhpRSrM5FXDQMiyrlZt2LzSva9xCVCSMW5020FJ7pkM3Mn2jkwqsZsl0MOsIb5U4FQs9jF5jzI5yvpTlMRwKwTkKarvQxCBSUTlh0qC/8tnz0Ye+PB5AJJBfImqNY2/268BbRlfr0lReJDRIxNJWDcaCn2slz8xUMYJOYCCbwcSJqSQ38jSJ6xKn2liVmPOclu18VLIHZSwkpE/TrR6vomRMfIpKWHgRv4rAOkk5G6zqKzZViEWZgkMalE7RqQa9QO1JnQzDzuJOVXUC8ePq+1KkkfPjE81axyvILCKolIGfuVHDAI2nKPZf2LLeD1o3rhvxWM3u1urp5Jx3spvZQcj+ajqOWdDVLl65UHhYpOl0JqapSCbqLfMuUu4uJDxTkLD5R/M+lUAhl3lz9SzhS5Z9wUTC8dNTQoh+glIyfbqck3UAfVaIWMKTvhjgOUjTArFnxm6VPcSLyx/ELy2fjQ8yTNtjwjeybf36onjT/xf36NB481l+wSi1qx+TkhOVj/5fru46b7Rw+jJy5BM2rJCJFN1sB4w/IKqmQwxFEK1KF/rgU2VRyBCxUjTE=","layer_level":2},{"id":"06284609-845c-441c-a8c3-f5d5dd0354e9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"授权配置","description":"authorization-configuration","prompt":"创建授权配置文档,详细说明DataVines的权限控制系统。包括基于注解的访问控制(@AuthIgnore)、API接口权限管理、用户角色和工作空间权限模型。解释AuthenticationInterceptor的实现机制和权限验证流程,描述用户、租户和工作空间之间的权限关系。提供配置示例展示如何设置不同用户角色的访问权限,如何控制API端点的访问。包含权限继承、权限检查性能优化和常见授权问题的解决方案。","parent_id":"67c4da86-576b-4264-b187-42216255a143","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java,datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:44:42+08:00","gmt_modified":"2025-12-26T01:01:35+08:00","raw_data":"WikiEncrypted:Jgq9fCpm/NkqSNIWYhs+n8jAB+e0gNtI/APb3D33r2Gcx4pP9wOkx8p5XAPb1XyRaoY96XomZcSS/CHJmGu+pv4fLZ1/9WIBgimTrKhWXI310Ih5A7va2P2uK+e4orFi6QqdcJdQBMmkGrkxgxbTdULTeG5u9iehm0RB20g/fq5xABl8kAs7mfhnTd56CHumBR//ClSi4ZTaa8faTDhXfDnKe/l9CSQ34DUKRKfiTxjJOqU8yRuXqy0vgbymH/EZLprUwLrfV09BLS0FrICwxvB3kqSeuz8ck53Dy9g8hBuxpEC3OuURxSpMDdYA1JogXKE8zzunaKsXZZQ9yWZ9zDshjvyFGAZNg5AnKKEAd06G+/DbO+SDqAxZRnU3/YuFs/UMmux6goh8XL8Q3I9YJQtoGSMK/j/MR2th7P9o/DYwHnnFxPB1u8e0eMBaARpjYrkAqCTo1ke4wVyktyIR5q8RQkcTzzkH2loqve0gGPcLLu5UaIUmLdMQiGLraGO2RJPoVqz0hf9u+EvUeBWB8LQRhCFnE0AnMdUd5LtPexOA29Utg13LtPr8uFEuu6vhjXpswUOOKy8u7oieohb91cnYcB8OYIgiDhRDVXgCv5EETFr3tlzKSB4YmFQORlY7gAeDyYgLESlhoWu3jBmRbVlOUV7nXjzEexCDSokSof2oGteA0Wf1kY2eD2hN1ju/fGDcK0/DsBf+zyScOytrFkMEIHjufyzPg/5LxjSYjW2HXrwimyOyAYZ7jEvvUHMBue6cGYm4Xcks5QCaqSjOKyd9EWy2cP8GQAcYxNqBCEUrd5xpAGK3Dr9QJ60oJWfge0IUF+9XQ9z/AE+14P6Mqypi0X5bsg9JNLp4avk2EgTb3Pb6yHVIVcsflIYFyAjixLnLFUdM5hb0J2f2/m6Rod8K4uCiHL1dJIt+gqEkIZydrWtqLVILW1Z4XaxRrHSokmp1LkCAdDdr3LwrqeVtDHEciDBGZF+Ba8RItTmRtmWzpg1+vCcbtiHH1o9kluy+y4jhi66kMj+9SvNq/NFyrfoqg6H4Re0q8v6mvSGV7Xei6UV4kF8AfxtZU2iFJfjiu/MF+YGSD8X9hrTgSrZTV5SkKjnTcHw+7Qk4rrmYT1gGfnv0HjzQ23/Ynt46MAfByx8UtctlWkP/A9Nhrig/BxY4o41QmVoTmj190j6k2W4bzPVwwhIWkN/tdeQelmIWAhNW/DQKfauUbrShqqfOi0Cnb10VGSJYm484IKvEmrehyD8vlaPMJZIF8Ixh8a/mPlVXjGvAWJgVpKCR56UDD8D8QVk6HjxkTK5/KvEkJmu9JU8yMVBPcNdfQp8RRpu5UQMol038Pm8yo424d8R+q96WOgGVDUnloIO/dPj+f+w+xo3UKAgWlVdNuZWVVL82L54PaKj/GehBgWihrcwiQg==","layer_level":2},{"id":"f3e24d9b-800b-4069-8a55-9e29462eb1f9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"交互操作","description":"interactive-operations","prompt":"开发交互操作文档,详细说明用户在数据画像界面中的各种交互功能。描述时间范围选择器的使用方法,如何通过拖拽和缩放进行数据探索。解释指标筛选器的工作机制,支持多选和条件过滤。说明图表联动功能,当在一个图表中选择数据区域时,其他相关图表如何同步更新。涵盖导出功能,包括图片和数据文件的导出选项。提供键盘快捷键列表和无障碍访问支持说明。","parent_id":"d9c6c09f-4495-4230-aff6-8582fcde95a6","order":1,"progress_status":"completed","dependent_files":"datavines-ui/src/component/ContentLayout/index.tsx,datavines-ui/src/view/Main/HomeDetail/Dashboard/index.tsx","gmt_create":"2025-12-25T23:44:45+08:00","gmt_modified":"2025-12-26T01:51:31+08:00","raw_data":"WikiEncrypted:nBJhxUtob+Ed4xp/EVXyZOkHD8LU2PpDEE8nVMrwoF/Ma6MGHhbPnKUN93UPFKaHhDDVw/J34Lze17GNWozrjHxSW+E97GIL/yEj73V8rd2+TOg5APnNvH2H+mKJ+oamikkCtdOOtCxxNj0rgKFl/wxRauUwKRSiJa71jpwVwBo/J7R9wtuwxXYThgBp4etIFTQ2beRFT1+WmdN+Gg8l7dQe8tihgSB9G0NzD4DTXcFH+YA7cdWsg30acxHLrZmzQYkboWoAdnNC/7GBlgOYhAvTYFe0uvhsr9A/Tfb7zmo/ZL8EMsPIyCt/40Cajv3uCAKG/p5eg/YyIXJ8KuHDuCHPzik5JP8/YMBRg0uzlPkLw6I4+9rRQPrOZu7iwmdBc8qEBjxm/1+tlcsQSLrM7xTmTCn2O3PdvsKQkNUuDa4CMhKpb51CvPQvc6r1ogMXsIuGnBzagQWjU0MMrlIik2TU5MyXbCE8bKPMHCW+iDZVEYA9xtEQCQhxuIhj13GyOA4Rn8HoNMyZn0XR/jywX7pOC+TIXJcISgugtnLNI9VBV2CpydxT63pwVuNH3/oGyWzDBK1OXaWEn2Z39syb0uQeEHueIYBkjjFbwRw13BHIGuckGUdYgHfZbIf6USCEl7hdLyDzvRO9ZAnqtmXGRuhin/xllwjN3QoZImKE44RQieWyAN6YtX35GZNdikDimw92SRPv5n34glvmTasr9YoTRKiwdG+HENydg1+yjGDyd9PgawkRyAH29bmlIg3D4TvNuJksRx++DfAizr9UhF0EJNug35jg3BNj2EiDzcpIN6QTOFYUkcAd1iqxfRInT6e1Xucg3iKZzoRnq2P5HUfq8k5893fr1UqGAEngxyKzWLv545R0XFD/0eaJ0PYLOPyT8zwXnFJ/S+G4m+GO/YqclmPgFnSz0oc+U8xuO39pxk845L+t5joQ4jo0gED5Yr6zIsyPWu+elQJMlqUFmcFxQ/+5v7rvcGQrOU2RZUuvNc0m8I4IXxX0GpsqDY0lKBk7lGWUQShP+SCdZ1OoFS0vInFm5rZXMtsiQrnSBh17K4VCFHqB8gZpLJRS6ImBcLnqmUB78nXmXgW8qO5oekocF8GVoNUPT45hCylxv3M=","layer_level":3},{"id":"27b6b757-6ebd-406f-ad0d-967146ad8915","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"参数说明","description":"data-profiling-configuration-parameters","prompt":"开发数据画像采集参数说明文档,全面解释所有配置参数的含义和用法。详细描述采集频率、采样率、目标表选择、采集模式(增量/全量)等核心参数的配置方法和取值范围。说明每个参数对采集性能和结果的影响,提供推荐值和最佳实践。解释参数之间的依赖关系和约束条件,如采样率与采集频率的权衡。提供完整的JSON配置模板,包含所有可配置项的示例和注释。涵盖高级参数如超时设置、重试策略、资源限制等的配置方法。","parent_id":"d3911c90-857b-4391-880e-b23a3893ee7a","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/DataVinesConfigurationManager.java,datavines-common/src/main/java/io/datavines/common/config/DataVinesJobConfig.java,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:44:48+08:00","gmt_modified":"2025-12-26T01:51:34+08:00","raw_data":"WikiEncrypted:YZI97ep9QXDPfRNDXs4+JGwAht1j93lelyy1l/cm5MvZivquDGEQs46U7sqNZlaNLGBBAfU+LdcgXK5d+q2Gfu+IWlEFDAHrkgV2Aaq3G8HH4e/fFKwxQthHUXkohIFKgHMJv0O6lNrxJaQi5ursnzd7tpygyUPMImE/jgygzvMHpDq66Gl6/Qa1m8gr2YnGaY4+AitwkXlKxyBkuwSLGksxiXLY9jMPmyL9itaPSR7MJWm7KZ+1nK84+ZS1XjzX8iU7JqjR16SByz5YIotvflnG6yRBK4vqxcTFB55T+yg2fCGBFYdka1Z4dMBXk8u8VZVd6rofarem65olJMs108+DvdgnS6l7/rQEMkJEerERRtDg5Wb2CIV4VdQgPVhNsegNClDRfS+AsQ7veL05vSadqa2hmTpYA3/ifOeg1X9d4Yk9joNIgREb3Oehg0wsLggSx1cHhASTxTObc3uq9q2Dr2JkjAM/5xupXrBr/f4WGEZgHw0LfbX2AeX+N2i/Fok9VjIPFoccTcTrYDsW3bSU4zCCkUwuoWiQmNCAd21qRg5OPqHK0q0Wynm5hjO+LbNJNi+5WJJnvEPV8d1ub4mTetUE713BLdWgeCACz60/r8LJPS0oeP3eAHc1C0wFpuWnQ4R5S6YiaPYLW3k1tscBVG9dGgpPuvTgf0eoN4Vt8XyhSaSlc2KiZOg3ONEtKZczq49cyZcXTwfavJnAJLCFhApTtB8vgVWd2bXNIM4Jhh+k2eFbkMgyq5tbRIRLYGHdt7LUPVZV2ViJpDo51q1MO6Lj61OIOUJAyjrqnw2gWNQatjyQqX8wccfLPSOqrH0MliKhwMIkerIddZQhEh3c8K/bDOmQiY2gPeltrSS+E5ay1EnQsXXzku1A6LOEA48YPlUbNbON8nP0ziXaslihdKgB+8zb9bS6rXsCBIM8ADqSyr2oc1N565t1XIcbKyx812RT0LdWbaSe00NY6a/khWjyhRkdtkZ5PSDLKUHlrkcuMiKX953rui6ZbjFgz8JbDnOndWX51U/ji1hrD5DzkXqTWreo+f+6DfQ01LrwBmRkY2zOktVq4QkeN+DMi2paKXjgentw0BlvZZOKcWwbStVm2CROQxCYZMxhzPARAji88rUeLIYQLL97ixvn8CW/CYzDnUoScwp/PvsnxST5+OqpLsehzyx8ATyC+OURFgQfYE5qt0WIURhp5GP59MKKlU+UkzKyMLLPeEw5ZiMUzjjts2hgNAjMsOUpS4sxD/1/e6MUSulGTmCBUZDr6wRNJcj1REZipyGJVmXvdIy8tUAYrkYx2I9ZIhuFmWJYicLjSWxy3WYSl41KG4WhBxyjv2pGL9H93G/FLe9qsthPLBJ3DZRP0ddgA01peFtrNcvKoYeQG8O6Ix0LndRZ4g0K3gVqvGQ+Hn22UwO9V0NWuUz2Vp8BySfwkffNdQfTZkksb1pc/V/e19b7UO6NDJVtSP9dsdwK98f0FmQCGwAYxebZ+hR3YKz5aozPqKM=","layer_level":3},{"id":"6f1a9144-3aff-43c9-84ad-aba96b1a50bb","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Engine组件","description":"engine-component","prompt":"全面解析DataVines Engine组件的执行引擎抽象机制与任务执行流程。详细说明EngineExecutor接口的设计理念和核心方法,如何通过AbstractEngineExecutor实现通用执行逻辑。重点分析对Spark和Flink计算引擎的适配实现,包括SparkEngineExecutor和FlinkEngineExecutor的具体工作方式。阐述任务提交、状态监控和结果获取的完整生命周期。结合代码示例说明如何配置执行参数(如Spark参数、Flink参数)和资源调度平台(Yarn、Livy)。讨论不同执行模式下的性能特征和适用场景。","parent_id":"5a95842d-bb17-4f7e-b3f1-fa2cbb84163e","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractEngineExecutor.java,datavines-engine/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java,datavines-engine/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java","gmt_create":"2025-12-25T23:44:58+08:00","gmt_modified":"2025-12-26T01:52:12+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJ/zZCsKLmc2OOCJskGJBMwT+aC6VsYnU2nAsx289m1vlXpzcETq6Kk4BK2ufec991Nt154qtGWscdZnt4KM5vbWxVECqkr17D+gucLIu1VpvWpMEc3xoKfibIhgGgZTuTdNpn1p1GV0yBywAu6DLWPdmBz0+Oth4YHMaI5ICeHLo8MLeli0LMI999x+F63xr7CKtKIx9tJAIlRHeFwovjQdErvcSa6RoXxMH0z+LV21m1a1g/pcMIkKV06z+42ZaFGOwfNPzBNyM6KOltULOGBBgZRI/za1TCagZaLrV6RwVHuoi2hPNRmnlcNPBCaY7d/Q7GHGGyqZcCz0MOjmitAtJSclHhxyLdBRffwYr3U7dmerCgTVs2PuY4W6NRWQh1Iej9UB4+1uwAl5UnPu6RR+aOA2+Rkq3SuwtWM0bnpJaZEmm6wLaPTnIkhECY1GjWh/gvhJPZNcGcjHdDtys1qn0DZG5KMW5u4r965PIOuSOplcoQgKCi2HRBuUe2CjryTnOaX2rk6xO9lm5a0uZuYCjq+Cdsb3LuXkxMNrQV7vMizAr4DOTKmirZl+LIVCqeAbgQD7nTmBrbJa2JWEEFnPeTLLbgo22V6WQa2RU943tOXgSDVI/o9RHW2RrAWuhXid1vbV9/KMpLivhm8VOXXVdWQN6aw9opO/5NL3QFUWy32b9L4Lukz1Npep2Re0JfGdZQsMnbm93/cp9NfjCBUZrn7ohlGuYSYT7rIq6V2153PAWnjGbqw6GeRYKIHC5Vhj1y8gDxNy8AkR+Fl+BEqmoJedCRjeffSPiQuZc0zS8NDvfE1f9aaWVs2y/c98FT5yNQ3jP3UhXlIhc8NWyszXGf8Y4VZx22XBy/iABfkX7oiO5nV4DbqSJmVgiFjONjf9KyatdLS9h7J1WOtVPeAsKnfy8lJMd3sQE616A4DHBpS0JX4roPqA7XeBsCKQt+j8t1iiOpM1xv1xK4yZEl+xbm5M9yIu+eB+AwCNsVGZ7OLx9pV+dq+2A2P9lqQ1gpK7HkONnGryD/wHwzlA1O2EudADLc3PFA4pyHjSeyS8zg1a7BLRZqwmviiAzoDZwGeGRd11jAUIHSxyvXiH4LRXkPw46rhcZqLMNPQdNpHAvdZdDizbOLklhPoeIvbmGTgdX2oA59BdNT/sFlcVldS+GKMpO9D4SMtebZHF7jF7l8H4qUn/xB1jVyA498rFOyi6G8GGjoXrN0EnM2OrfXUA5UeTfH/uIXsq2DktMC4NYCLrHTAMbcF6kd8DYmOzNy1tXfHqIIff/ThIhVQBCzq4JGlzS1AvvvY0Ub9nox1AgA2tf45V2saPYeZJ5ywDnFuPWVER5z1c3pCRGcRo6hz6kNXTCk1gFYuMyVTJcFH2vSgz9QncgCDiO7ola4FgixahHphpT4HR5AfOuKS3ftYYkQSdCpX2b+Ocovv7SncSHWCuqdqwpEAxw88Am9I0acMDnh1GrgsANxmc5Q/8cDICmYXGKNIuVQyl7nmin9AcfjTUUFpcjTlz/YvDVkxMqam4z/SwODaf8wi+Q3KVi3G4aL2JKsCcpHJcnRT+MrGmlggIz21bs1LezwY/k+t18KQI9JtSC+fdMvFNDLLVApZWLfmLR3B6XO3mrbKIju2Z/Ck5f7C+GCY0hPMZrmQihAGAizEMbqWNG2wQ4lIRTfncG9N23Y4KlpUu1eoW7ldAW8Pt4H8UTSBAv6r+oTJuxqpW2N9ixgRroyxshyg/kij5m15IKrJe6DBOvgzXcbz0RLkmctwxl4FX42TFjIsKmhA==","layer_level":3},{"id":"8686fc3b-bec7-4b41-ae35-31b1eaca7987","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据通信协议","description":"data-communication","prompt":"深入剖析DataVines各组件间的数据通信协议。重点描述Engine与Connector之间的交互接口设计,包括Executor接口的executeQuery方法签名定义、Request/Response对象的数据结构,以及不同类型数据源(JDBC、文件、NoSQL)的响应结果转换策略。分析ResponseConverter如何将原始查询结果统一转换为ResultListWithColumns标准格式,以及SQL执行过程中的元数据提取机制。通过具体实现类如JdbcExecutorClient和MongodbExecutor的代码对比,说明协议设计的通用性和扩展性。","parent_id":"42102899-382d-4ae9-98ea-ab19ba59b352","order":1,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java","gmt_create":"2025-12-25T23:45:00+08:00","gmt_modified":"2025-12-26T01:52:53+08:00","raw_data":"WikiEncrypted:/j3nBh2eZGsOhaH4GyKbokjMNG2gHwklf+NXMMvbavsK6ZnSr/nWPgtHq5q1KHuHPHdFqFUoCL4WNNmOFfsHiwYf+drAIfbqFNi+MXSwTGHxEO2kQI7CdIz7NQCD0U24CukDNKwqt2O8C2Wj8QvyqmIsPI4jsJWxg7RAAbgYaVObs8bzOwfBmrJCg+3IfRwW55fzE/MFLgS2668SZWqILlxK+1tTcL1YT9bgTHmIT/j/GWiDyiKGGDHXbR+/cMlYst5Y5gGMOAHt1jMBI6c9lJwBxbtmChdKDJkQk5rMmYO+DSEiW4K1aX+4HomFMDzztfT5GbF2BR80zTNQyz0Hmlhyq/rpeUYMu23jz5/PBUcTqSJzYFp0sdnzylFP+sJxUBw12hZFDE2C4NzKSqlqjD762ayA3Mky81mIiTZL2z3NTJxfCvecKapyvhTn2+bp4X/5FbAijapT1yUV5EPgmxB70yg+JbteEaRf7Ok7jwmG1aEDOV6J+w3ePywLhMyak2jFpmVHFBgtwKVpzRH4ohALyYBTvdoN/RWNzAgPd4uHVUkMFG31EFsAEPUktfaVJgcwXjRXr/VBhxQAPEIWK1b+hRKUhfulcSH0BXjXDDyL6Vi6BGQm57adEJR29FpnRrf+TaNoikgsZ+fzzRwWmFk9Ud+q5PcMWRoGF4WGU08/NHcEDrQPHgWeoZ/4lQn11gaxIBgmBdVtcljRtPIl0kWpEVU7V28QF3NIVPzwfQwFDNohgpzzpNu9LhXlHNqYQtDCvHTTb/FTSj/f0m6y0KXj8BlB9DfzG8YdQAf+apQOmOPaWdMnDLC75ZwTFVqqNhPYQW9Oo/hf1aaTeglfJFz+LRLWg1TXvt/Yn905PdI2rUcHZ9ykQr2aMgCFKbMTugy+tt7SWfuDVFidMbArBfIFed+iyqsJVqrv/xg286Wwss1EsDmqqOx9fcOXDHHvRfqIuEhczoYev99cEeQDSCAf/RC9VMFFr1TBuvrMApn5rpw7P44yj8k0auU11jNErIFZ1kpDRF9KGdq8iLZAGaXGbxF5aKRaGY92fdThyUKpgkvvTmhm4Yh4AhdjdjuW4+LF0pU68NUon0CK5V3hmGztU6vokxMW0Yuxelop+5j3924SfAAGFW8D57wd0ckMhlKZd5AtZ1SifTvAxry6MKa482M/6I1h4fK8XKkn2ojxykPGpUqHX8gkdr4hwlOo7W2sYJiajTuVWLusnyAu5s8MqD0E60KaXwFfYpL0TAXlzIHyh4GqtQjzXvApcP/jg/iLhEMfZp0yiHRqr7IgW4qUII+7klcV//0IrL19krKJpJq5Vjmq7yrfSwJr0/XIBQql11M6I+NnZM1CbbTZg4KLtGud2qO1M2oz3KSgJkYw9YTVSm7fnrxPoHbL3BbE6HCSL70MeS2yMJXoPgnE9m+WZz9zPvizAAudCsINrzPawKFK5eumeRgYJrqREyGKZpGdWg4jTbK7W+MSX3Lcv/v/52mLqJdDA4k/7KboFLMOQwtkx/Q+ZHC8UpKJUgol","layer_level":3},{"id":"8ccd960d-5ab7-4c37-baa2-3ec94067dcd8","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"服务注册与发现","description":"service-registration","prompt":"深入分析DataVines的服务注册与发现机制。解释Registry接口的设计原理,以及ZooKeeper和MySQL两种注册中心实现的差异。描述服务启动时如何通过Register组件向注册中心注册自身实例,包括IP地址、端口、服务状态等元数据的注册过程。说明心跳检测机制的实现,包括心跳间隔、超时判断和故障转移策略。分析服务注销流程和异常关闭时的资源清理机制。提供服务注册时序图,展示客户端与注册中心的交互过程,帮助开发者理解高可用架构中的服务治理机制。","parent_id":"4fe521c8-eabe-4899-aa88-38fcb7db2d6f","order":1,"progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java,datavines-registry/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java,datavines-registry/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java,datavines-server/src/main/java/io/datavines/server/registry/Register.java","gmt_create":"2025-12-25T23:45:04+08:00","gmt_modified":"2025-12-26T01:53:44+08:00","raw_data":"WikiEncrypted:vMsgMax61wW2sTWhXd8DH9jBu933PY8ImW6mX7BXFeD31zAsbZ2uCXs11TMKYdoKZd/d/xf6N1N/quztxwYuutceGBfGrqrMRaJZqiY3woNttncjMPTHmjldidRbL6umsEr0L+FJHNM7d/7vSG6zbTIiIBwU6iI4CCr1GjzhWC2xZjuqwCUMMUCKwK0ltaxEQVess5bUPkYGcozbJwdcOjuTuKyXxjgL9Ht6sOMyNK/QOhqUvLdNpsx/gukgDvzxUZ+7wOazOTZHDLq+/DDfM5W8AnUVqb1YzSihFfpQuJQy4IdWbk4OisKXKy1qRko0pNXcRB5Q4Xs+eqSb/pzwCyPpaXxsUONr5LHdgnn8hcL+Nwwp0ImuSATukMCTT9QzfYMBIiTvL59tWThSgxFmRwkdMeQYknW5VdPLugAMdNbboANpz3oV7y6e+F3Jw0p8hmisg85Vzqxm19YbXX0WGGEKLycKjvFm/PRVFJTNaEwIBh3Iny0AVx/lH4SYKt7WSA5T25k86ASraTBU+K86UYg+qJllw45iJ/D69IOjEfytZ+r6a2BwEEEXFgbcWQDQPJ5cmN8AuWeXmaEkKV0dBNi76S6jtUE2lr2YesSYAMhREOBLNml3j5EGQ9y8YcSUpk9hlV3dDEQ8TTz+kXBKf0cD7WaRwiSFpg5meH59HRN++A1AeHSj8M70OnIGHemguNYrOWqQGcM3DCCcaCeG/TOWc9HIXF9cMkIx9vZxGgSwaiYh7fvE2d6cfrUHwq0qKR0prPbrKMgLyxpASXHJtEKCSTX/TW07F+RpQBouAP+Ar0z9LNfWsokSKr5OpM+I1r9zvOJvijYZADGU0x1T3SlL7ASaDr9CUBacpLCY6tnMSlH+jednw0gMdwKOFG4hKUrXBayeu1VZRtnTnmCGY2SMzntK4dav9Kr56sYygoL4+3/M+BcEae648toGbodiEEi3Oo5oDsjQKgO9Wt7Xw1N0SzcsK6/+/EwRvMZpj5Ia3Dd00IG1asal7LmvrhRivqAIsTCM4d+Wo3jm2L1kOP8TCn6oTxv04h9ydblEf6qlrYalgR+VDdnU9RIY0F1pk6oJD7qLY6Epc0Oq51rrBobO5fqDoJu+5jtO3ls7jixN/wBtyt2oxWLqK0QfLxsUlUTjILAHMEEFG2O0NAyhey9QF3E7g3qY6EOLbgyd5XBCDECg5Fp6A6ZD1uAeFnK5OjshqyBtfGuZrMEonu4w8eJun1qZoX1QZ0Br3NhB0BTTu99wS1exTwZ0a0G4KREMzjQiRaJDT5zzHs8Y5XROEF6jQ4c0sqm9mWV5cLxxYc2MBKtbEzQHqmA2OgrN/VtmDqGnPQq2/OdivkdYRB76EH8Wj+EhUNBd+qE+hRQK8k5gfcxOprgNvh4nBUm0zF3H3fl9pGSusPkWbm1yQK1QpFRAjA0YVGcZ0VFUUXt1FFIeRx7C+L9sIo912a5xrghMne0OGzmeoBr9B3u0qh4kycAhaPB0O1UJjWF8/OHPxvC0F5Zi5NEcR2DeSdWm7/RKhEGyYE19zDK5RXfQH+IcL68FlFUTd9IOuhl7rhxAkiPFQ6IWDREcD2FUOGnCXULK","layer_level":3},{"id":"8a7821e9-9176-4c43-ae8a-64769c6958b2","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"跨表检查","description":"cross-table-checks","prompt":"开发跨表检查规则文档,详细描述DataVines支持的跨表数据质量验证机制。重点说明跨表准确性检查(MultiTableAccuracy)和两表值比较检查(MultiTableValueComparison)的实现原理和使用场景。解释跨表准确性检查如何通过主键关联验证源表和目标表的数据一致性,以及两表值比较检查如何验证不同表中相同业务含义字段的数值一致性。提供具体的配置示例,包括关联字段设置、比较字段选择、容差阈值配置等。介绍这些规则在数据同步验证、数据迁移校验、主从数据库一致性检查等场景中的应用。说明跨表检查的性能优化策略,如如何通过分区剪裁减少数据扫描量、如何优化JOIN操作等。","parent_id":"9b5eff2c-3130-4124-8dac-52560ca652a4","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableValueComparison.java","gmt_create":"2025-12-25T23:45:13+08:00","gmt_modified":"2025-12-26T01:54:08+08:00","raw_data":"WikiEncrypted:2GoRefXUXXQ3Xwp7OyY9nr1AKYKpl+O7h7rPMDy9+OaYPQeTnKu6purA2Z6D848PC5WO0qgaAxdmA6EzDkk0Ll0PjTccpDVpBP/g5erIGabWkq8H7MauaLRTqMGqK1XYjQyv7xWHJsDBCK6cMw+Y4kLXmiPiiVvPJmEiTT/sd51Wzr2jK/mLYmG+LDAMrhdQoyGQqdt9RPXmTlP0cOGIw//a5SzurqfZ4ht4gBPSr7fbU7RGjRzQ8Gt9fuQ7MM0yHSFdDX2VIbMx5NYDU4EGBscayMR2FYnK6N5KziJPOs6gxd7hudrMlJZnFgtGSyHVlyChGMYFQdmeaGfNdlrCtvajp3ffI/p6egHR5f5ZKFPnA01Bc5QxKdiXMkvMEKAPdx04M2T+URk/Y3ihDGM7JQmkC+N94cUS+B99yw3gYjySDaP2yx4NRE2PML/6263HJMBbqYLblkhotIdkO9ptho5hSOhwUaaukL4MNT+f9di7N1E7xWVeDLXLG7pJcysaN9yb62MAjbhEX0g5IOzeSvh++XAKDVSiasPGDSqpceNoDKi1liqJ15lOIwyz5IjOC77Ci2nsLxsGD2H7Y4wiq4zi20dO9r1KJE+5L3tBNxgxtrf9d1Wt1Yz4k7q07QlegGfgv68VN5VFsjicjARABSaYe8Mt/l9e5e4iDZH8VaH6fe8JFZKnxtF3NoMbLivbUTvv1ZoSWiwS3pS03ezkqQaHgiHh7BZPFQQRhVCSEFC6T+ETfKa9osGFIrsUofqwv6ubGUtFzskH7IMxcBgVjfSt7SktA0ZA3eGwinqT1lQvyaOqo6K6RsBKspf8EelWktugu4lZsjJcagL+LhyYPkbwTPfJ2tZBYJ3iqZB2RLmf/F4AhhccnQ5OdO5Aj1bLRV0H7M+LQdO5+k5OojXCNpqYQdcxDvteWF4vRE8g1mFLO4P297nvcywIh5JeH/6f460kP4s3kUXS3MWlN38Uqr7GICW4jcZUKsdQLBlI09kpO9UylXAF3+ZLrLq47MywXHlEUdjkNL2masW2raVTD53MbOpRdzilhA5BFGJslU4gU7zV0gg3Uo1vmGBs3xlD+qVfMpq+0iZlZ0Nae3cdXa4YcjgjrMMkH7aoZd3ocBs03gkGWmhb/TzAKPCoGcpbpHicj31z8tFPy7v60bA48zS+IIUxpPJRU3uvUmnU867cDtt7WeQQs5I/BvLsjgKFIT43TAnyJs5U6u5a71G1F4yutK0TQUAMt0gJWSkgsRiH/xKL1dEL2bRce9Lfml89ayhVVgi9v07iLUM8cJlcjMdp0h9FraMzS/hYP7HKT2LqE4kTyWlw3c5CfD+Vc1i0ozaxBjIA1KvWnm8UP2E77+/JMItrvu0nypv5RGfDk7A5PC8SB5t6e5yBiD3vshxeF1xWd78uxx04aakCSRIOLXSTZalU6dwejwFcLCd/tkvh1ln8Vw83uGZkjYTympH5WQvRiNBquJ/BAHBeM3Ja7OJ29R+2YCAAEcy1prRED2R3YIzvMepr+c1sTWmHX4KH17AAMaRFMQI7mo/WeUnPjkizmLNpQebbS/pGiqRyqFe/kYj6XgQvb6D1BytbS2+4","layer_level":3},{"id":"5a5f7336-b3d2-4a29-bc1f-277b3fb38204","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"资源配置","description":"resource-configuration","prompt":"开发资源配置文档,全面介绍数据质量任务的资源配置参数。详细说明CPU、内存、并行度等核心资源的配置方法和优化策略。针对Spark执行平台,解释Executor和Driver的资源配置,包括内存分配、核心数设置和堆外内存配置。针对Flink执行平台,说明TaskManager和JobManager的资源配置,以及并行度和Slot的设置。介绍Local执行平台的资源限制和配置。提供资源配置的最佳实践,包括如何根据数据量和复杂度进行资源估算,避免资源浪费或不足。包含资源配置的性能影响分析和调优建议。","parent_id":"9f664f1b-9947-4d3e-a6b9-ef1a47485c24","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java,datavines-engine/datavines-engine-plugins/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java,datavines-engine/datavines-engine-plugins/datavines-engine-flink-api/src/main/java/io/datavines/engine/flink/api/FlinkRuntimeEnvironment.java","gmt_create":"2025-12-25T23:45:14+08:00","gmt_modified":"2025-12-26T01:54:15+08:00","raw_data":"WikiEncrypted:WRaIw5LcDrebk4yzceYz7/9UGWh5b64UQ+eU8CZ0FSrEcvSP8lYfqcaTbx34wKpQw9QKSa7bgTiHkLL++G6o9YIsEnNysrvXFUgnqo07DcA1vvu9Qv7Fo1TMkPQKGqCpCz4+SIBAjVdVMdAUaVJIxfD9pqWhpT9RSF2rx12PMRSdpO2wPAvmk00OnkBb29Wa1Km44YNHJMDKFNQHdTZBkrLXVZVw5NR7wA0TGFPhF3xZRWGogAtXoOmMnrkNNHWxPTYelKnVMzYHiRqdF+YvvTku49AkRK3VJKSlep7fyrAmAsb3IMUXL4pbNQeuZO+7NmG/PUOtNi+8TxKzqfLd1Ojw9mekjihkz7EIgr9bCrNFoeJ9dmxeZc326LuDcNrxQZbSW5g8/YoF7xoH3ucfU2gOzeuTxnNjRx+JfrvPT4egTk7lTs0uSVtYUqD7a2sk9xZ6zSqjolAnxJxh/uzmDPvEatjzady2RIz/Ne9KPwTOnTm9HWRrkoumv+KyTaqWjQePR+0phSpUBfWSwpLghLJ1P4xKAJri5HCyNusky80N27R/hrL9Cpill+b/xuRCjPPF+MtSR8hnLmGhUR5/1MnVLPpKCHWmvhWAx6vV8O96rJ0BtCTOEJnjl3uG7UhvUsuXO0Z3Qfq8OtxdgfRqYNzxWQx7BTPrTn3/4fFQBnTI1AOQPy06hlQTSbNvL8pK0BcHvbpj88m+Gjd2KS6GSs8ELdHuqT1+3EShmDG7JBjIedQbMjl9UcYGJGmj6EVIQbK8Splcnxt98O7NtM8QN9B2cm8jKSAuOeHiEhGXAYdJhLwWw0oBmoG4nzUTImiLy3f2LEA6JH/93tIvIjpw+zfxLQ09S4nK5Nq/B2tcSKfk/aiZX4U5I7+RXDEDGATFiz46YFAv4aRRk03yx8VHGmFLOsHW1oWBKHiNCBNWbDLz6uwJmQVjrOJ3GEnNg6Sfpn719NKQorh2BPkIac8U4NqC6edA7kfFdoVsOcFn/wMClVpWRRL5oSHo/5lH6GCOS9M1JHMDX6kOXxV9HpAAAopAsyzeBqU8ZA0/HiAslGjM1xfDYmiGFMheaX9UID7jjenEJDJRY7TykMDBmGIZU8MTtMWuSKijmXKoveUTJLYopQdKGFCT8y65Mro3XHRTyxxc7nQZFJIvyudoY0BqsUnfUs2DYso2/9MuLEZUxp/mza+e9R7ZvMRUEH6DaPjduuR4+lE9VJ4c7dxwL7rgM6nF415OsB1Itanx02LLX0oUGrHME+r+NmHBaAG5mdG5FJ92tfd2OZiwJX5Wb2BfsEtzfY5m681eNG2dyge620mWqWSgZjjtbeFiw7GRAAOCmTUi4iC38b75nYvZ/WWjj+fCgE/nBIv1JanI4gqxFmF7FQjpp80J5bxuNQ+KydJ2T6Ag4Ie7CIh+KdaVsmE+MlN9V8Piml64NKj0tOzfrGRcscyiU41GHzxnmk0VgXGmEyykkYt3jcgfw2BUVT8rJbmfTQScHgj5wND61Y/zER7sB+P1SAz5uHSX3G1KOtVZIwFdDL1bTqfqtcvcltLWwHcLr8Nj6Xbu5qDKGSgNtwHJOKhUpGTWDx6cxlVyzzOqRiwnHUUxabcLGibuczGf6RXTRqpaY+n7rJxkhxMbbBgSFmXeL/BiRuX7+yKtfGk2uFI59viJxH7WK82Vytpszw==","layer_level":3},{"id":"0ecae61e-c4cc-4be3-8858-dd5fe32600a6","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"预期值计算","description":"expected-value-calculation","prompt":"开发预期值计算机制文档,详细描述各种预期值计算策略的实现原理和使用场景。解释固定值、历史平均值(日均、周均、月均、最近7天、最近30天等)和表行数等不同计算方式的算法逻辑。说明每种计算策略的配置参数和适用条件。详细描述预期值计算的性能优化机制,如缓存策略、增量计算和并行处理。提供预期值计算的扩展接口说明,支持自定义计算逻辑的开发。涵盖预期值计算的容错机制和异常处理策略。通过实际代码示例展示不同计算策略的实现细节。","parent_id":"89150110-41ce-4344-a684-350172827c8c","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/AbstractExpectedValue.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/FixValue.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java","gmt_create":"2025-12-25T23:45:22+08:00","gmt_modified":"2025-12-26T01:55:31+08:00","raw_data":"WikiEncrypted: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","layer_level":3},{"id":"d0247d4f-b68d-4c7d-9ab7-65a926f5b82a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行逻辑","description":"execution-logic","prompt":"开发DataVines任务执行逻辑文档,深入分析DataQualityScheduleJob的执行流程。描述任务触发时的上下文初始化过程,包括配置加载、参数解析和环境准备。解释任务执行命令的生成和发送机制,以及执行结果的接收和处理流程。说明JobExecutionResponseProcessor如何处理执行器返回的结果并更新任务状态。详细描述任务执行的异常处理机制,包括重试策略、超时处理和错误日志记录。提供任务执行时序图和关键代码片段。","parent_id":"4abfa320-b04c-41ed-aef6-bfdc2fe13c3a","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java","gmt_create":"2025-12-25T23:45:22+08:00","gmt_modified":"2025-12-26T01:55:41+08:00","raw_data":"WikiEncrypted:jMgId5h0EoZtwilIIkOV3oJsjW9LMW/98gu7PDAT82JmFeXghUScwxuTiueLIe+DuQ4KRuowc++tlshcDOdbfpiJh/XHim+uKr41FF9cawyUOlIwo52ijipBJAfxxhvN8Dij2K3CpkIvmHrbAqy+x8qVMKUzNYAy5fFCLJgdvK7PtDHzIffHGCFsj6qyVznKL2cypl7+SCR2DE3t7Rlu3Lc29BEWHyuQGoY4UntGAc1TR+7NCbWZRfbC9jD1rcklxImZGg/H3vRnxtL5b3RRD7uWwJWZlPKIhjof/GIIABQVz/FuQ34G7tfE3qTbiTmZqnsbkEssPPqadq6O71TZjHJsJOrLD68nD+7G+Jr4ujbCp/coYcKAZvImlHCxLMnSTJ1EZ+XHTYgvLDzcQHMSK4m5mbQQtVN0a122tP8qurUDFUWoRSDx9R4zq4/XF6K1zKqI87QqSYBmqgwlQnkiwzpruGPlkv5J7a34Q8YWKWxiD/qhbrTzpnt4Y0hHwMDXBTUNIZBr8m3u5YaMHIexEFb1rqec7hXvt2pqGGswJWknnXR5R8EXmyII1GZ3jbefviR2+PK4f0GXKopCQ4oMR3DOf+fb1G8W7yCNULwiIqVD6c8PcjVqy2bzfvf0bDDvFDW2Z6jx/HfwuHBwDZA8EAxxeXqLicSdZaJVLqZwQhmjWQJDILmvBg8fvno5i45aPSfZs61bxPE66NR+2CnqxA5Kffks3AcuLgX2FrF3dUC09VmVNdnQqheScILTwwLsbcoyeSxICfzEzcIstLCEdm97UHQKkWen7hrjvdwkJzhF/mIfQpSk9OesBTovNBXI9QXOzRjukp0rToEYYIcesK9Rk13JK5SjyuE0rgMGCw5O0qzWv1hhnlMEoozLwZBVkm01wvIPpGyNRASoyMc8KY2kqy2ksTlN62Z2yDBdVomc8JdayhFCP9WJh9E//8XC1Wcy2alm/1maqrn4f5NVk4D6rw67D0ySxc4tRXXQQJV9kweecTI/517zq+0ChqNAk9h7IUPGaGIV1p4tyWlvSGnTdQy119GoWXAxwvkon96bJeNy7IsxO5vs1MVsy1GOWLK1iLQW8/sa6Tn3VXqh4PUFMT3prJ02gNeo2M3G8dF68XzfLL+rqA7RPEextRFpuJF6E1fB+u3qzVz7mgv9ISrnXZAfMTz7RkbxEdXj7od5dLlo5Ex2pTsSbmquHVXSinZJOEAsCnc0VCBXTA9hlap2YOay4Fv0ynKreaQREANjxApxcSDWDyN1gyrTakuV62wQ01e2tN74mFKkH3eP6fvZxfCAMEcTFFSn1RrPB7hwho7am9/iy93gzCXGRoHz","layer_level":3},{"id":"2afec718-6318-40a5-a6d3-484810b76536","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"生命周期管理","description":"lifecycle-management","prompt":"开发数据质量调度任务生命周期管理文档,全面介绍调度任务从创建到销毁的完整生命周期。详细说明任务创建、启动、暂停、恢复、更新和删除等操作的实现机制和API接口。解释调度状态(如运行中、已暂停、已停止)的转换逻辑和条件。描述调度任务元数据的持久化存储方式和查询机制。说明调度任务与其他系统组件(如执行引擎、监控系统)的交互过程。提供异常情况下的生命周期管理策略,如系统重启后的任务恢复机制、调度冲突的处理方式等。通过状态转换图直观展示生命周期各阶段的关系。","parent_id":"a2152a18-ea14-4a41-80d9-cc7645d5b0c9","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java,datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java,datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java","gmt_create":"2025-12-25T23:45:26+08:00","gmt_modified":"2025-12-26T01:56:01+08:00","raw_data":"WikiEncrypted:xbmA/Un8S89yBKRMe6iygmPunGjAmZt5nR6C20hh8kB+XbzjMn3D/0yK51657jG0GrDeNatzIRTS2WLrcSiBw1XtPfOh1LyokS/4NtkneHSvjhqqu9CNUjujVJhqmowBsl80UdB96TkQ751YtH0vPWufaSFHW18GBz9GnAIUnVYMov5SVBYxtxnazKlKXOnIxgAm01rHtnri8KtsXbw25FIxFDpj1UM0Oir+sQnFoP+IDsnrvBLYygWKCQOp23sUjX8sGS9aUD6hZV6s0TAE49MFuwWv3Uf68O9LirIb6F2yHSgaBl2SBuhUJhsczGovXbUT0OZSFpfxRH+j2szSgOFoMe79pSV/suEJ1uW7x8yvCwJbe8LhnPDDZi6KtQI+G4xPGIRBBallVufERHwR8WSRYENjKLcbOFmomp549LR8IRlhLPBTl2gUHeg2Ty3MPMQ2xgP6lR36nxsKU16CpLOetWpI8Jq2uK1dD033gRnsAdTqNH0JkZk6sZvnzjT+o3BnwDodVw3WjptyCw0FMNmubxTbw3DycC9HQ5wtvazTu9l7+2sWVSpSgErBwbrk/X5Kf5fsJeUVTUMtEkbNO/ELKpyErfW6BM1ON9Lg12injigy8YFtEpALQeUjfjiqlKRIIyODU+b4yj8RS8j7F2IRldzMBZXC5/ufovVTgJMU2J+a3btl14kQEtTe00RLRJBA0nAUxNNz3fMtzGlyxw9FR3bROdfUOsazlRi4d6RJv5lvnkddTjzPqbnwbkqNLT7/lP/K+6UWmK+DnIcm66B7pb8pXJ2P8a7JptCmYm2IA6ANVo9NHIAbPovhLxxfjps71VZRfyM5HQRwb6ZLec3k0s0hu5blvKNCFUhas+E1IF2jjU2yKzZqDGWo70Cj6t+OePIXw+cOZEfDsjrgHCk46UKFt3Y3y0W5iBJFQDqwJZ6/vs7WzO0htROrcd4VuQhmZvD8NRhG8NpjwCn2NUKAzdbFbmLqRA433eOSWVSBupovevySwAi9FIGbPQpl26z0NH5MoTE7Y305Z0O2YLjcqBxuee8DqJIYVU1C0x8Zwv88hqVmsyzsD7NdS43b1jcjLwE5vIEb9b3OTgxcnV27Bxpo3byJhiirOSn9Ir3WYIuYx0MT7Qe33k8iegITYbwr293Tj/C6uaUNE9sgwcBtqihSTfm1FvHZ08gVSm+mv4W0HasYHUAmBp3ixzrLyU9DGul272o8sFS/tNY0tdu3yoh8IntnnpN11NmnJw6N3/0FiUqc21FTVTB3vgjwC5CvltQqJuQmtbh5nMSaFix+W9A8aRT853vIJZ9cbVSkuBNcHHxEQLa1L4oCgDnNg5XqZKfTwNk/PLKQZqmkGj3YEHHaWgRZJSehnKGe4E388ukVzBnzMFOnl8pgz0Aw0ty9bqykAE0F+g9OsLvNJW1CVoFzBizAaq+2+LWOzsBq+8QQbGmqrE1cFCg8ysclqx3YNp0gHdFY+DK2O9f/HRIl/M+DbQXjCNJDxwi1a8v5HEzFNVRKOgCUCMTPasx1p3RS6EQl8L8LSb3Ok90J12yrIkRC1fV6ESr6v+zrGEGPAl6osdUOBQVYlNViLaZV","layer_level":3},{"id":"ac49273b-a216-4c15-845b-99e5397bb798","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Yarn执行","description":"yarn-execution","prompt":"开发DataVines Yarn执行引擎文档,详细描述AbstractYarnEngineExecutor的抽象设计。解释Yarn资源调度的工作原理和配置参数。说明任务提交到Yarn集群的流程和状态监控机制。分析Yarn模式下的容错和重试策略。提供Yarn配置优化建议和常见问题解决方案。","parent_id":"20510b1c-4941-42d9-b461-571abbf86340","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractYarnEngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/helper/LivyTaskSubmitHelper.java","gmt_create":"2025-12-25T23:45:33+08:00","gmt_modified":"2025-12-26T01:57:36+08:00","raw_data":"WikiEncrypted:2n/lFAsaMT889x3PgBOkYGWqGaT+ByBjTFxgj2eKZNcvpsBWlNTUfF2/kAFYEn3dKuJLJC1u1tUg1EYS/JlRSXqb13amy/Q1DD3aKa9BSwcHdkfDf/yCC9u29/Osq95bp1ZXhskoL7QlHsTeMP2CM7/NBjBXr7mu9DlOPCayp8L4ZJXKmUbrWWjdM9BPw65PUGftrlugQLs3rLnUewIW/eQXbdL0LVRVN/IhaBXFeZv3G/Ui1z8BoQmZx/kDYLP1Y9mfPJ2Hm5je4nd5oXPxHDgoUQGHw5DVDFYkdvuQaR8TyriXdCe6EuSiFTsG+YyNhCu9L9fci0M9m6oyklcYnY+SiQzbtF+AzKBgmJnc5XjRIIhGChp6+N4iXBBFM4OCMybrPMRtQAnBnGloFwIPXNlSblpf7c+BPq0YyDm2N8ApwENn2a/c0CDNN5Uobtv+qiIJSzQsdq7W002QioN6IcHCdZ1mTwNebzuV6kuk352cA3sJh9oEkBnrkZzPbERKySHZB58+Am8M+Qq2KEH4/aTIEW0rardkmgc3TmR2HJkzEOPvePxBUJ8gl5ypQMuUzoVFUhhwv3mf9ukH8Ep8+zFAk5qDi94RTrMyGShd24Uze1nEFo+RvM6LliLw1cSeJhUFwoLed8EgUbyWXh6ZLfjHEYNszBtxUsSZOUI9q2eZkCG2+QwMINSQS2ncQ9YKf2x7J68rj94Cz9agMlNSDebOx0yWck4lSfJXu+OboipQEBkRWj1bPhRn0u7e10Fz68WUOnWlHW7+WNxXILntMmZ6dubgbLXtoKitsH1XNFyfB0JaA1s1A40EVSlj9wru3F6p9h+XkvRlLLB4oCYa4vRavDX9EhqXH21h31B6KHYR8Av4/g4xhfYDXLDA0wHoUMIi/7P0HFFFGNi2GyIxYPLbNRdHGCVg40/o0k3f8YxY9us1MafmFr0H2HwfQqD+vbBkUKg3d8dJuerdpUvOKvnqPFahNFfbfdqVGiz8lBflIFhszyPEZrvGseRoFjjQas3p4jgx/U+sheShA7yMP+h6OVCCXIBt18AgI1/LlMitgTSUZAle5JiyEkSmCnZQdqXP9xdBfV5Tq9aHbOIzpw==","layer_level":3},{"id":"ff00b230-16ce-4cae-ab84-1edefb13079a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务参数构建","description":"dqc-parameter-builder","prompt":"创建任务参数构建器文档。详细描述JobExecutionParameterBuilderFactory工厂模式的设计与实现,如何根据任务类型创建相应的参数构建器。解释DataQualityJobParameterBuilder和DataReconciliationJobParameterBuilder的具体构建逻辑。说明参数构建过程中的配置验证、默认值填充和异常处理机制。提供自定义参数构建器的扩展方法和集成示例。","parent_id":"bbd65494-8a17-4b10-9e78-b360cb044f38","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataReconciliationJobParameterBuilder.java","gmt_create":"2025-12-25T23:45:47+08:00","gmt_modified":"2025-12-26T01:56:56+08:00","raw_data":"WikiEncrypted:gYHZQ0OOk1FCQz/VnOggF+QjAl5ig3F3J/f7tJu2KraDII45XCgpdl5DnuZj4NGtZPaUcZ/0MV/Ji+pEfMZKwg2mybP8b9urnQz3v60HrQ4jO0+lHhL/2AhzjtGX/PSwodj8KfsaAESej0Hm6r/gmgyNtSMP5FpU2Vs1b4zLthOUNUdZnjcte1kRTMNo81+SBwyFjcOooa/tC56YCuSbCM4dUMU8Gv46W3K/vajwvrm+xZN4tb9q8X5PD6/wIF1GTxRAuUzUS+XHmTfhhG9o2X0WTWsGLktSeiKjSilIsHPnAPb3sFm3psigEB8QVWwRWLq6m/Q0APHnpB2kw9dmGyClTFBXts34wIARqxcblxoBtfV49eRa2OmDjwF82jUSD5H1yMg0tHqmRlwJOSvGeDXc/pg377G7jINxAcERuaVttEg36S92rRtfUqw0aew1Es6UbCk49A82eMo1zE+SEuH+tvYvB6SKkMOvBJmEwcNMVOdxVG+A9EP0pdsv+Zhpdzp2lv1OgjrLEkirjiw2FUbc3bB0jVFxBeguNYcSulDZKQj66pYTPblQgUzF2uY3nbW/tmff1Qda4C2nmToCVvJSRC//TbReEPNQGPDY7Eudx/Z2OC08mV0AlUPXcGZGeoB1DKhtb55TBxvjPKVKNnSnHrf7nThMW9kFA2VWQH4XcXo/Bh5TAqn8eaSCFAucl5NPBdQkcy0pmFYK6K/dwnz5ZsKCL0roJQ9HVJuy4l17BZS4j9hTepPOkZGLUiOjiJ0KellrBLX9Iooxb0uDmFR0+K+CP9DS2hZjAyw1nkAnBEbYxcAMv3V7zOPtgaZhLNLCsoDojLW93XIKXolME0fFPuiwSWzeSrVFK6zVR4DmRnbNcuJeS+tuwViSM2sWVbjPavro3vxP/pMAA/RPq172FssUFH4AaMG8LEfeeBGQTfVosdA7ryD+2b0op305ZFqgUVdrFaDTjT/jzpEaA/4vflYWi+R6w7qrvk1cPQl+AaDV5bj4pE9fQaXJdPDlbzQ4R8pASVL6IbEGApVNE2lnb7v9tyLsrEI0iGhZ9ZC3h9FBn/DyQ/83QvfwJWZHDgjY5ac8ybsVEbFSe6I8uFmW823jjgYhNFGV5nt7MjU9GDaYqFuRmykIT+V/dn/Bh3VyOX9BmMAGhzTDUHGkBwPkeSMvVS7cEH+9C5qauW/Z0h94ZfjRWbH/7sccygeoAWQ0PqDSsMIvzibXQwa8O0L2Tu/awEdqAJyLOcSazzKI0+gy5jwZFYwGsybSZjGXxDUjlbm1impsvmBzzawBc4ezcNjbphWD8gdv4039948=","layer_level":3},{"id":"0f2a22f3-1d66-49d4-af7e-b67e98911858","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据源管理API","description":"api-datasource","prompt":"创建数据源管理API的详细文档。详细描述DataSourceController提供的所有接口,包括数据源的增删改查、测试连接和获取数据库/表结构等操作。说明DataSourceCreate请求体的配置参数,如连接类型、JDBC URL、认证信息等。解释如何通过API获取指定数据源的数据库列表、表列表和列信息。提供测试连接接口的使用示例和成功/失败响应。文档应包含敏感信息(如密码)的加密传输说明和权限校验机制。","parent_id":"251acb67-6d5e-45eb-b64c-94b11aa2ce30","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java,datavines-server/src/main/java/io/datavines/server/api/dto/bo/datasource/DataSourceCreate.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/DataSourceVO.java","gmt_create":"2025-12-25T23:45:58+08:00","gmt_modified":"2025-12-26T01:57:35+08:00","raw_data":"WikiEncrypted:645v1LRE6L7I6hQKDQon7AzQkMzYnbLCX5IS8/1ihlFzlEY1dxta/nzMXEq/dzVyYCw5/scA4sqVEFuprtqLpNb8FFFhG7mVuMTauf5FYphioneQPP/2xepigLuxorl2vOCH3x9CyCP75tZf3AnDBqumXsjCHoI5cRHXBovRHb8tir5JDUebplErjTVLE8HvtZL8HwL2R8bwLbSo93wN78QeNyePlpaVhyYvyq3icnQ+6jm4wslreG7GbIjER7U5NukSelQ41+GXAOOFn1fIsCgjz9exkNyZ76LbnIuuTQnhAqIZEwS0qPD01sQPEsq6z0BqKKKliTE6HpQbjb6PQN5c1pt2FSyfcNxlQ7gPJWBgDAmWaVtX+CGm9dl9lKwUuRdNeTdH6/ksZ4nmzguO0dUK6MGj1wBtEHy171tQKLwtC0CJ4kwDZQ5nlCEtw6IeVW4xlOIvox0HUrvXRsfMUjgiN8ofnCU0lQxJVlt/wuMvy9fnpPvlGOu3pGlkZFy3pitfnMiG4+a96Ledh37A4VPg5H+DyfJQFbnkQShwgmU7mTZFbIDs1fAIQGhgfg/6amnqISAlmrrsws6WATbM9apk4lspNjA/XlOIW8gD4HcRSQBBCvBJf6lDiq8egXfn0Nzwaqmp6b7cnxggCJxecvijFR4ncWcv9J9tlm6RM01TUcCZ2mmZPltXZRV5mXTw/hjwxXlVDJL8S8VJOoF9T5aP5CcyVxP77/z4GX0x+sIhwLnoqAjgxCXXS+89GEEDmR1e1lFLavQ9uN48GMSluDDz2/ralGYd5fPsQq0t8pIpoFe5DJ3aoKNtFb+trINetTp9rPE/ILy05A6tpRnrzlifySxSGETXojocKZBWaJHrgzhebvEyuaOOiGqPB3YBk2xjAS4Kedc+TAA52PNrZyWufBSIMkuduL3K1k31uusy2uoE9Q/1gbZffYTbYEQIVYXYu3iqhk7njcpOHdKP65dcCr2sLjLnbb9KqlNHjVslwGYuF4Rt0KTCSFWLrk7QocIUmgIlS9loo3AQ0BNWHRrwF8uyDsXS7L7O7KyJfgaJ+McjHwZ5EM6oK/bDhIIG5A6qa5tAIYxYTu3YKAVzPd3EHHAEvyc/j5hz8kvVidwUynoExl9I4xGIKR9CRKQjwAJBSmEg/kU8Rqz0fd+DQL0LdzaKXN3RiTnj1UXxWzar/JkTec2Xpr3lInCpvoxPxfoFphaISi724lLqkLdWOqUeF8nHUEv8KkRz4yiqIK2Q79drNmPoXcJw0L17jN1WqbyRQ2e0jxXxIBWR0JF9afqlYczEJ90euAPoiLu4c7MOMxvCE/GjseV9k59U9Gyt","layer_level":3},{"id":"75b89676-2378-454e-9029-3ee7ce30ac24","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"RuntimeEnvironment接口","description":"runtime-environment","prompt":"开发RuntimeEnvironment接口的详细文档。详细说明该接口如何封装不同执行环境(如Yarn、Livy、Local)的上下文信息和配置参数。解析接口定义的环境初始化、资源配置和执行上下文管理等方法。阐述该接口在隔离不同执行平台细节方面的作用。提供该接口在实际执行环境实现中的使用示例,以及在自定义执行环境开发中的扩展指导。","parent_id":"724f7889-75f8-4bdd-94c2-bc5fe8255890","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java","gmt_create":"2025-12-25T23:46:00+08:00","gmt_modified":"2025-12-26T01:58:17+08:00","raw_data":"WikiEncrypted:A5b4lX/1psCBl0fM2G5K/RIZHm6+K4EOr6EXPcMmIsqQfSGnF21acwGc+t6Uk91C64C3doHzzj163kEm+WacJ/yNmCqCuyeiUVVxw9D9mhUclif/SxzR/vnOyCfzbFCFhF4lw0VLGuaVR9UN4nWgGw1aI2yGur4p9Zw95QqyVw0bTaZPevILjR944fjp+NNPa6fSWWpnx0sXXr5NLU6Js9wNZ9LqPic9i/wujnPd8CUyFganbZwu4dZqlU9oqBNFo7/oLMgEOt4AdihAp3TdUT20iWRFBZvYr39hfZU+djF5DVijJmsFR1WueCjhKxXXSK2i8UtTbXNpLJKDyGuWziW9FOfrRB4gi4DEPaS5WPf9oNU1q5Ci5eUX13QbjPOPKXTf5VTTqkj1EokEzOi25HUgeVn7Za20rXiMFiXUBeU+urxrMTIpfU1gs342rT+UHeCl+A9QQGJ+vXLk+y6mgTDt2+1Im7+uedSNgd/LuD3Zt4gCpukt0iCJTOE8ZI0m3+hIK0y9KA9t9/HFyqrzPaSCM8PObLcxEbk+uFHXB909KpoV6OIptfsku7u2rGX0PwjCm8laqAun9fQVXjd2blzrgKHfA55UKRLz56j4LpJJJIYh/vjH+DnoVt/De9EDZDHDzbETQEKzq7Yr5Zy2DURX6dDUgEYuq7rslvZkYodRUDMyMHv64MnsVuuQ8evknf8+NAEoH19sbGvyrKZrjgN5pgGn0I026YCFSsYyhsUpi4BPc1WE7mEtD23xhU4FTK9Sj2ODq8REDgkgbR+Y0KKgxTgabw8Nz3V5daE7Ge9iIoxDxmklvVW/KQFpu/9kO95ymHtClX1dR93jVGgCg0S17lxS6VMWVoOf2/8MjaXCAeffiU9Irqkxvb89vR95XB2FEEt5lqnGIb6GaCIsLWPb7G7l8CgXqn9CqsmnRtXyIYXeigNJChVpW1bzYgimrI+/E82iK9rgNqAkymnT0r2EMIOhUe6pxXYhWzbmVQkAblSNKwF5uaEIppDB/Up+7TvlnVZqEVB2rEH9LAFp1Q==","layer_level":3},{"id":"b6915c42-1b23-47b4-8a82-8d77f4d06fe7","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据源服务实现","description":"data-source-service","prompt":"创建DataSourceService服务的详细文档。详细描述数据源配置的增删改查操作实现,包括敏感信息加密存储(如密码)的处理流程。解释数据源测试连接功能的实现机制,以及如何通过datavines-connector模块验证连接有效性。阐述数据源与作业、任务之间的关联关系管理,以及在多租户环境下的数据隔离策略。说明服务层如何利用MyBatis Plus的Wrapper进行复杂查询构建,并分析DataSourceMapper.xml中的动态SQL实现。提供数据源配置校验、连接池管理和性能监控的建议。","parent_id":"ae9c4797-fad2-4104-bb0e-09c584c89e78","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/service/DataSourceService.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/DataSourceServiceImpl.java,datavines-server/src/main/java/io/datavines/server/repository/mapper/DataSourceMapper.java,datavines-server/src/main/resources/mapper/DataSourceMapper.xml","gmt_create":"2025-12-25T23:46:02+08:00","gmt_modified":"2025-12-26T01:59:40+08:00","raw_data":"WikiEncrypted:yP6vl3GzzNMVOI7+ToNUFYSYb9TkRmGQrZhpVZgXOmnLPIB6swd3GhIz+knB2sIeGkNnNr6Hz/9M9mcdBfqnJtZHBjKhQ/XOCpocC9FpqRwZy7koXiSgp/K7xrY0a63+aCIK10u3dNywcN+BxIMi4JU8cem15ZsGnWzCrcx4Xn34DT8cyEl3NWcOpX3hah8nSkA15vxPNJaEl0XjpNh/oTUHtXoFX+/punPkmG1w3PQJJ1NlpW8NcpopYhceuaWZC+LoxE2YqGHd5kJ23ehXhmgvvgP+EQ4r3hcLXjiqnDhjkjhu2DAa64tGqTu76lnifdllRFpM6mfAOqn8T0RGuTuEr5m1KqBEob9V47tB41T36fbg9pEGPwqhYxBOY0/mh4g9SHH6Uwi3kc91bvJ1BcwCUmSjLQrJlD9GgJ+iMvQVVg0YRXm1wHKz7FMc3V97RPuFF8RPBCHY1TJnq2SG+9xeKvDOSMteKQO8EzdjN0bjs2Eq0VfpQ3jA42GRxzVinPhUEWHv6F5FxQy7h6DqkBBojg6rliR+GK4RLfg6JGYAP6YnsUlwry4NKaRmmqiFL9TBWsD8j0nFiZUQzCv8SNu/ZsQQGBmh1h1mWxTeey8s2VnK1EMVE52zZPPPijCv4ieqwMUh3ZRaIysrmjt5wVjDNtB8Jt9lhpeCQU+KvtQvgP9YsRXIudVS6uIr22kIfiXZe2n0mWZbgLa1SdmhenCYys7CqcTEB/7QBRdKTVMWqie8prUyKnGO+p6AeBSqLMNdGUVF+PRzse5SmM8iBgz+Bohwz6NB6gyAMpFUprhssKZPa5MiGG7wEut9GpQvzHz8TvvIVCMgwgnYkS5P06Cmrq/SDwYJm8XSSelZcRjr77pOUBt9URMiatqNlorSCMel4hzOMiIB9oegErSjKrGKPtpfA/5++JVPMUTNxSiw6+5rtwH+P8h6AK2sLBZXv+PoNpvnuqhOcm6GFOZf4SDA8xmsMRrCaJHO819Gpl9kVp3utyUhhiy05HxteZfyaYV+MOX9sKGd0QZU8Ya+8ltwdWjmBSIDGFZye2tXd3leUEtVpXY7kOv1YdTTiWAUTExaxAIsnuacifH95VcEVB5QNikiKh1RyTcgtkTp/bxRLe0YS9CfciZfWat7fZptyseQTeKqZ6R2GFrUANDohJTKfM6PWelFQD+0sWFD0RS3C6O9P/RVx6tn+QK38uLxl1hGRxCcEKN9LoNln3HrLd3jLmMMNhSOIbzIBp1rCbUVSRBFxB5WPCaKvfqJ08jDuDPgoN1qMrxWStlt044srspvJLblJr91d1YrBwYSgbPxQsCnMJogC/YS0G5HNNhXtqmd2DNh5fsJzoJnGlLDxeRlhOeQdtAQUrrn/gGKYAoQtjhNszwrmL/cmO6Rzg92Os7ePW1lSU58FuxTMOMC9wTnLIoAG44/+w4vxuiOlcgsCY739Xp4Cqn5Fe1qYbkRkPAcsGqw1ymPo7UqszyNahtEBEosebB0gi3dhen6tt4a5i1xCKgsqvngCTH4jxK1P7B7wOjh7W58dkCNm6gA4tKaKlSdKAdglqe6qywanhE=","layer_level":3},{"id":"490f16ea-d490-4acf-bd66-84b831b25bed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Livy执行器","description":"livy-executor","prompt":"开发Livy执行器的详细文档。深入分析AbstractLivyEngineExecutor如何通过REST API与Livy Server交互,实现Spark作业的远程提交和状态监控。详细说明其会话管理、作业提交流程、资源调度策略以及容错机制。结合LivyTaskSubmitHelper类,阐述作业参数构造、请求封装和响应处理的完整流程。提供与Yarn执行器的性能对比和适用场景分析。","parent_id":"07b63f3a-0384-4d83-9231-bdcd684fc464","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractLivyEngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/helper/LivyTaskSubmitHelper.java","gmt_create":"2025-12-25T23:46:09+08:00","gmt_modified":"2025-12-26T01:59:57+08:00","raw_data":"WikiEncrypted:FM86MRbIHRcFErydqrYvs1u+buinOAgdyfyhhhRf4+XuzO2fvCduzJT3lP0qspCX94Blq5TXcWimnRvGISNGfnhehferRW79HFQSEZIcCpYMa2nGguYxFLqupBDUwC0I7NGt/mnZE4jbEgwuTQE4/Ge7eMhClJdXF+/gMq3TEt47TzeVx1W4feBnmxFu75/n84ZOGA3yqCAKHoaicA5y/C8cSmY4mjVISO2RyUtXMdx5ykAGjFNcTEtCML0c9yA6s3a6zyQfZ3Emd4J/02vILWE8lUHHxy/h1Qz3eVQWfB3FcDplXW9wR5i2y5VuvMeZZjqEqQrPsE90Wqq/afbPU+WBA8REMQa6DtUCjEzo3tVlvzaktNdD5soDjuHEJXDEkftQt9vTSopVhO1eaoYyTwTesfnBIgjSPHjI4IZi44OQupIXDBRhF7F0V55Xnh+lofCslMDELkCoEOzm/XlWFLerYEFmbS0ToTI3oueZO1OM66F2uz4jMlSBCFP2nW6yu8YbE6mQL0qGc/kGKwvLdb2nysHOWSCBPdz3E1ohXYcVjtgBjnzn6O16fPkPe9HoLG99Pw7jAWGLaFUUzTozzKWP2O23eGo64fh8Tu6qlhal77VwK65j12eOryT280LuFCjyeqb1t6jBuu/uYe7u8x2OUrH53wLiPTGi60tOgXTYwioGehOYcXa1D1M0o4uPXCeEYb492aKoGo7yfPSUlVYJ/XNkec4QhUE5V4dIe1ZGxoyCu8ilf3pryHne8PRFLuQnjsay95m6fer+UGqO544l08KhSeb9SgxAZsJ5+fLYyu89TYmLiWRH7hF1007ZKGvzA1ZZZ6XXIZTMbhPNIG28ojb1kiZ4EUybLmxiEtCRr2jLh7dCN5T0Lue9uZycNnbN3dwL7BrrpUdU5Up9QvLN/l51IphHy7a/wdVPMN46SLYTAD12exl1N+MsggdhdnWOVtgdIBVLAqXB/T7ltXGUSAmPJczp0fDPrOkXH1XO3hM3a6AQNokkt/DEJ3Uoj6qQMAOEQL6MS1HQpmLLsFUEJ3++Q1dGgYZpb54ULbq+xfkei6m1gRe0AzwzTqnrPm+Moc2drG02Svaw8u7n/R7U9MKMjRgPhbyHUcT6b4CTIp29TbjUoKyDCUpYnrh6","layer_level":3},{"id":"03c2fc14-d1f4-4beb-a517-abf842d366e4","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"跨表检查规则","description":"cross-table-checks","prompt":"开发跨表检查规则的详细文档。重点介绍跨表准确性检查和两表值比较检查两种规则。详细解释其业务场景、配置参数和执行逻辑。分析MultiTableAccuracy等核心实现类的代码结构和关键算法。说明如何配置源表和目标表的映射关系。提供数据一致性验证的最佳实践和性能优化建议。","parent_id":"84f45a10-33fb-4d11-96bc-c2372db645b0","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableAccuracy.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableValueComparison.java","gmt_create":"2025-12-25T23:46:12+08:00","gmt_modified":"2025-12-26T01:59:56+08:00","raw_data":"WikiEncrypted:2GoRefXUXXQ3Xwp7OyY9nr1AKYKpl+O7h7rPMDy9+OaYPQeTnKu6purA2Z6D848PJjtWKEHW/1nFmyLwW1leeg6rZdnECDQDytwq8I9wQlgU2Baok1GMCgE4I3pgjs+zoo+b0e1W+UvzerDeJ4aysfLKxNmPHEVdje4IUG8tP6diPcfpy7v0bHwo0S2uywcxTOD2CrIKu9lZjcZ4TLEtcTAWuIlfT5+2gfdeW3cY/Se1Z6lb8gzQ/O3qVlU9gO4i+PhtLtY9Wdrra49Hle2JuwKzOR/fh0lq1HRG4i35UcjJvhg9czEAn8w7TPlwmeXp1ClYLxmZ1J4vjALMhyhkV0j3YYueut8hmaxg8JisfOZ+j9/cO+UanlQLOftsH2KlFcXISonKbQcjU/ckrEwiepObvOFqiP9FtLwf2n9z2TPCDSrXNkuGBgdMXZCE41HSpsYRpv0MB4d23ZdMy9fOR4Q5zZEhZi+bRwSIc3HCzUZLDu1CXMycZNTpdjuLgT+kkMlH1AiYTs7NbQOKOdBXcD11vgrOK4gonJJHm36XQXhpQ6yLSfsHeGVggBdg/iD1qP4nW6vQXTuVoxi9bCR/lbb5QTPClGxnh/wGcBzhChvEIzv3eLH7f3u9CIvj3PbJD7/l1BYM77FAj6xn+TGq1Ge5sIiub7BDerDOCsvprXW9h/QQcGyTQjaRx65N5xueENxeNv8W8t2WGcA6Cj71wEngxFRY/Ult0fLm6VnlZlJxt4B7Q3kgV8GJTt11vJSh1cbEvcVscEWlD2EWk1lTLacNeTIUgvvilvZaQU3iujal9onsBXSZuu8ZcJ7yBbWS70bA3yIvss9GGM2aiCcOFDKeL6RJ5gXyOsHdcy8ZU/wgXQNTZvPMiCLnxDPHxoGd2zYk6EmtMR/zrIPQdADWUcOlEGlhiWxMIPjDP3PxR9kNZLxQ2MTtkCG1TZciqP/iniyPweorsZ5Q2krzKL1tuBTs0s8R6YbctHKB8ECtyNSL7HH0FTsXnR9owtPORxn2Q36RGLXQsDF/EqN2Lo9nFCQDWdgIWItBxi0pTYKeqoiXNwYNe3HBfcvdICJUIH/tmXKhnMHKAuS+lxug3p6K6mQSCb9FjpDtoG+bq2t44gI=","layer_level":3},{"id":"4877b289-0dff-4019-923a-91501c54a7a5","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Spark执行引擎","description":"spark-engine","prompt":"创建Spark执行引擎的详细文档。详细说明SparkEngineExecutor的任务提交机制和Spark参数配置。解释Spark配置构建器如何为不同类型的质量检查生成作业配置。描述Spark运行时环境的初始化流程和会话管理。提供Spark作业的资源分配策略和性能优化建议。包含Spark Connector支持的数据源类型和连接配置。","parent_id":"aa8efb1b-1c99-4fe2-a451-746364c7e416","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java,datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/SparkSingleTableMetricBuilder.java,datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-api/src/main/java/io/datavines/engine/spark/api/SparkRuntimeEnvironment.java","gmt_create":"2025-12-25T23:46:19+08:00","gmt_modified":"2025-12-26T02:01:17+08:00","raw_data":"WikiEncrypted:M+m5dxh8XuRtgpG2DvE8kiaBiL153OVGLywaGxLeDPYqkx2/7+YVezPn/eOLioehnrSrLWKDrcv47XTGlh9tI60kwqirKGb+QhjL8Xock3TtWXXNtDSwXW2i0v3JAavmxRyZ4utSkxm1OkHwarE3vXofJE5BnzmcBdmiNyy7gZReCVBERhdwE8GlSc38sXtt5A6a8ZbDdFiA9fnMAMvw4vIBlTV/C28aYNX3IVuQqfIET72qIl+EEhfBH852zb6ppt4M8qLLKug16REJuAW6L1OYmryad1nvjYPbaOnC6Dj61bijZvxvqjE5aOimU3VJ9NuFruUSOKIIBTn4IeUB7CPpPxbmEp0VmafeC5ttmqam+NlkzfwDbRc4pnZDaonx632rVqkolRZhTxoNc2t2GmG4AR4ubnpgy6F1mHAmRSUZdjxzfOrUVbZI9dihvSuNM0RSkSJyp9lYteiMEmo78O9dhd12FiQ+FQyeKnvWzSrYNLL8YcthZNIxvDHDZmJ7Ply2zKGCpG9EzBVdf1kU9GG4WE9hFx3fRdqmZqHHLQ9XoIHq+dPmZiO+sOl4LNaKBWR5BUE9uB6rdU7W7AkPugJcWIcDYztQyejoXLA49MTzDEY3vMABH1JMQu1Q0Gyh37LLGDSm+5i/CPQEpa7fbL8hSrVFq2GcHvocC4CXSvyOec7Hwkfryfby3cIx0FiXiEzg8tyzEWXdS7mqB29HujFwqO/P5qwWfWdupte+7SMZOoUFAauabzFu+SZat4b+glWDC3gjpcEQYBQGEfcVGtepKVK7GRN2IExkNG1Nzoa464JID93joLcw/roi9uSEEvRkh+riu6ouDC8Hznxw5igkqQoqIYKS2OxgM9rKvPnFSbL9r/PlUrBjpWC8frG5OWLPpm8qz+XCoAsAHoG86+tGMeLkenQEytn9EPgMYEruST1UIPkFdXJOluz1MMF1qCc0Inb6OLLcvC0qYORdzHnbU90FFLAtIllpqEDuQC7xALEFrUPIMC/tRTm0NSLKXfzlO9Dy0IQjdQGPwyYqQzCxLFFCZ9zTrgGhcFmpU/LDj2StIjEjF4Fd0poyk6NS1OmwE3v5ubakY8s412t07qIb43thmYeWp7sLJL6kImcyePMVVzlDmmtIXzR2O09NF/dwz5yfs/H/yRH3ciZJhI2CFGitfT2yO/82MrCBxRi9XMR7yTvfJ2ZB/B4SLGcbrPz0vDcZjiYpPkn3l9pPripSASeTnnsfCDDNbN8inDoKVHG93BpONc+V1sNIoAnFMdcqzIhra7k4OvhEpvcWlqgDvTT4Y1beNwpnswwdBuIE4ImP8oIcKQ8/ay//6OkdGn6Qgy4igXFWxxVmNYJPXo0J90Q4WO5KKMAKuB4atE6ET+008m2+UPagJZKwxukS/QBl8i1+bB4fBDdHxMeHT6Xl835aztb6vf353q1KNPI=","layer_level":3},{"id":"489baeb5-14c4-4d03-b73b-be142d956487","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"时间序列平均值策略","description":"time-series-avg-strategy","prompt":"创建时间序列平均值预期值策略的详细文档。深入分析DailyAvg、Last7DayAvg、Last30DayAvg、WeeklyAvg和MonthlyAvg等策略的计算逻辑和时间窗口处理机制。解释这些策略如何通过Spark引擎执行历史数据聚合计算。详细说明各策略的配置参数、时间范围定义和数据采样方法。提供不同时间粒度预期值在业务监控中的应用案例,如日均交易量、周同比波动等。讨论数据延迟和窗口对齐对计算结果的影响。","parent_id":"a42f354b-55a2-4356-a7b4-d94e20a79fea","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java","gmt_create":"2025-12-25T23:46:23+08:00","gmt_modified":"2025-12-26T02:01:52+08:00","raw_data":"WikiEncrypted:uikLfhDdd9ILLOD3P7p3ZqH3dt9ZrWbSeM8o0siEPOnz4FLRCFORIAkU+OCzyVIe2rJ9hGLH3zEuwRp8ohFXjFdJHWy6qG4rObCWPiakEkGU3VojSD3KZV7Q7A6NrtnywFBy2nttEwR7FwIdOid35sWnr3KAjH54Z17witTMci4iwdYt7/aatCtQMTr++SNyBGp2p1WXN2taP7TxhaJhEg67GEfSAdBfS6v9IdW/lnR60d9k06/k1pqbTAJWZ6IRpiL2I5TeIDnejcyxIQSZpMUi/SajR6AFQHcShI3RToUoLM0TBg41tliOFlUq9uN7SZdY+ZdHet2DFn2IggVotmUbBgwoXGzCK13/d6timnjT2s8car0R5Kjf71rwtfWOtia2ANM99JSYYmSKqt/ImPql7hGHFpsyyk6au9Z9ZBTXyFFQOsntpRsctPTPDOTB8k13wtrAAS5UxqzgPmQ91vCB+PdEsI0sRCXVnBrks+/+qb9IvIKD/3bhtvAguMmpTsrYcwPvEvFxIoBMYgWjIEaDWrbR182ACjSXmqCQ3F6MAZJB58SvSjSXsL/SJg5zkH5svQCwp8p1iaV4nr5TtEwujUT5izSwsrUB04Sn8RL3mmbsciV77wTy+MsFvpgkIKRXUGLPraLORUXq7Ai8/0rDNh//PBhS//ALtGtRqSYYs+Ym1VtOmWf4EjEpCVmNJZpx1YvxoLHjMEcWDAFke82nW3xa1qrP+NTQXbLovKJdLisfWwLTJwCDdEQ88JvA4QWl4OC4BqAYsUdQVJJHLFmFq0p76dOz+Z5sw7HxSFTX6ljCqol5cFNN9SbvwSG4cyCBuZq7AwKodGdiGn4lesqHSPskxgLwxJJSR5czSOf+xobuOo7E3eVraHMSMIw0w9VrvWNxER/W/IRIingZnQWDWtDmSMEdcgno6YI2fD36X7TSDCl4pKhBPmY9J4VrKNuDGZKHr2XxbPsx9M3hacpOm1zf0k5iKpMmb3ET+9IG0JSNH2BBqZD+1aloymLY2lk7N9bHa3uTGErKehnWUZ/V5/PyLP5hRfBcQidi/U7cSqOQHwpq+S8Zlf4dqa6HuqWa9kwAPuAwnxaoICgXLpayn+vwvKptClusewBor6wPGtzmx+0snWf17TgZDDDv625Pjqe0xNTolpCjIU78yfzPUtM2QwnCwWhfYp+cg/xwpMk6txhzkCV/+2gsPcLBqihmEUnHAACz34s2+9NPHJKCd39LF/6k9KdK2DDc5nI19jg11f+ZQkF5WcFwhR29vCqEKKDkUZPmcH3I3Q5rFO1+NGJEECjuD4rRrwxL+tTzGfA9HZeyA2/Bxo8KENsuTKyF79v1zkcKPsF5fKA4zPdwjdx2AxGth68zQjsRSMHsNNMU+sjnxW2z5WAioP/ktrx76adYEqQ/qLO+lRjnIC1d/p8iR+f3vdCP/PXHepXFvdDpUbuTgnQVhozC4Tue8RLegKby6ieT8SdgEGVlLBavSmAEWDS2B/g7N+57NMumlLdNTXBLr1WvKGzvtcVBSUayv1Vio6MHGZIpPfPhCmNIz1qI0hgSGZT8Y/gknYh8yLXFHFmFVqKWycSERLwUPVZocXAhRwep4ICGUtK/58BmWhxs60mpsNwavK6HiGFo2hLkS9SmhPcQufq6BjvIQsfIRk5UZOBeXjkzOOgOe72OUo03OaCpeRCn7iG/Cg/t9tsAUkGPAo2FQG5VdMZHIDRUjK81ELAom4VpSu35+KzQuDr4qbem9TsVbXfPfCzRVs7BnYN+uzmPJzlijQciLlhtJTE4p98WY6nD3TINdO+yX7HBZVTVDeeWOfKqaBA=","layer_level":3},{"id":"e6987f90-3aa6-4080-9d4c-676c44cf7263","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务管理","description":"ui-jobs","prompt":"详细文档化datavines-ui的任务管理功能。描述任务列表页面和任务实例详情页面的布局结构与功能模块。解释任务创建、编辑、执行监控和日志查看的完整流程。说明任务调度配置、执行参数设置和结果展示的用户交互设计。提供任务管理组件的开发实现细节和性能优化建议。","parent_id":"21179d81-91c3-4822-bf9b-316332af72db","order":1,"progress_status":"completed","dependent_files":"datavines-ui/src/view/Main/HomeDetail/index.tsx,datavines-ui/src/view/Main/HomeDetail/Jobs/JobsList.tsx,datavines-ui/src/view/Main/HomeDetail/Jobs/JobsInstance.tsx","gmt_create":"2025-12-25T23:46:24+08:00","gmt_modified":"2025-12-26T02:01:58+08:00","raw_data":"WikiEncrypted:RNda6fA7bZG8k8VrGWZRlMlFWQuvRCp5XtPsuV+xOzmSY0AM22UvvDQT4l+OLpysA2XjvUqzsasgxlNN9/BpshHRgz4d4I3mizf2vCpAdm4FtbpDwiMWw0RCLO/RT3gnxhkxD4O2u+P9fWSv/imIZ5xOV4mwp24MVHoWS5Eq8SXCbB6BClQVSyFcQU1S4GRUdgpKkGYUvur1+pgnrlRyqRmp+H29lo7dJdkg3IXtUDTYqpn91eH206Wt0Yca3+8pXcCwqhHRUbw3F/lgkU5uwKUrdoO8C+g1m5n7qiCb0WvOxo4yroDFHOUwTzzPtcODhECrPaj6bd+9EoHOJVTI2laOVxLaTkkUI/lD+nmQx/HTpefmFuEBuOBLlbWzENzRLU5r9E+KaiEXRLGB1DKJLfPuXZscd5NlgOEXC35+iiJvNmZ/6MJDVlA7SlqNjyDrqftHxmga8i7dcO0qOeFsKUZ0gWnivGoNz/K42UgHJLbhcrcHWv0MU79Uei3Sh3CW/aEoXF8dBesDATChN4SQK0C9iy5JmiyKmkayiIE4SvzewDWTgDIq7z8iMO8BzZ85+krDvO+0Kv2KpmIdvqPjAmcJHeGkEwFX5DQH/550wXwlR94vB4ozwjquqjurXrQfDx5g/s4DCgUyr0NDTgsdyI+uclRyJY7nDnBwOUyt6+QHZLPhrHu/QQ366g7IU33PKgy4KcZIOcMUUR7fq+3/ZFj/imow5R54HPgnDCqgQupehe4sK9XsE82BTjB5C1Vp5ta0ey0QJKqQ0OyBYKI8hlktXWQpbP0WGu6mBHKjF52ldCErlWbaubfvMpwP+eKmIv6LwPBzn3Oq0V/uroW6osT6hI7S91VYs905iNpREOnAwC9u8G+WdgWk9T5kTtjmMFSbaWzFoBHaAR0BKQ0PNLibQXB/uAncDRqzbN03xYFLohYYyWFG+GKWjOQxnNNs+tchNjzt6pnJdOhBArwfMldClxnuV6TEFwpam6pg7ac=","layer_level":3},{"id":"b42b93a7-226c-411e-8a13-c7827801d7c6","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"生产环境部署","description":"ui-production-deployment","prompt":"创建生产环境部署的完整指南。详细说明生产构建的配置和优化策略,包括代码压缩、资源哈希和懒加载。提供Docker镜像构建的完整流程,包括Dockerfile配置和构建命令。介绍Nginx反向代理配置和静态资源服务的最佳实践。包含多环境变量管理、部署验证和回滚方案。","parent_id":"ee36f1eb-9d0a-46b0-b7b4-ebcfba792d43","order":1,"progress_status":"completed","dependent_files":"datavines-ui/webpack.config.js,datavines-ui/build/webpack.production.js,datavines-ui/public/index-prod.html,deploy/docker/Dockerfile,deploy/compose/docker-compose.yaml","gmt_create":"2025-12-25T23:46:30+08:00","gmt_modified":"2025-12-26T02:02:18+08:00","raw_data":"WikiEncrypted:AAT8g6U8FmDTqB5HMlLjeM6PQ6E4LP/F+R9tvc7VlRoo0bigOz5gbV9eM7/XQk15ycyACHIsLAc1+OkHhF3gIJBZtgH5Mp98rKaOWmd/Zs6sPtTUFfcf34qD0wtn0AO/2jluNdcdBsbb7vAT7qPz4+QURLshXwS09tZJ2A2UKBkfbJmxA+VomwBCqS6YOj8ALRN2kzOT0vg95JoxnCTMBs+lFTNYBT16JPDRrgTyGke1yPJMivkllq17WVIR/Q/YuX37Ri5rHZaIRvNbk85JX4RGzBxeYQ2rs43Be4Ux14ryUi+LDlgaeN2y+vvzZIv1VEKpgf479CiQlp31VFtDnj5QOztNgGOWdBrpvw4Q/b59atgMbMVZG6giPe6lCK6ZYh4+105yy4chSqvu9t0YSWpsL5HxGVFlL2ygo5tBWpLyksCXEzb7SbyNuZh/eWe/nYYEFlEq4zdUBztZg6WlHYmW/HtI2KEei2oFy21PJTixWAiNQFCjd3UvhYKl6VZa9KVT2USgqAiHPJqMiyt7Cjp4Ob5AnDTBaXCA+82tH5NmVtDw6/ztyuqOTx0FqLjVRmYkAvphlSTn/GH37PCu+CEo5MVfD7VgAlOcjGDHKiPaOf1rXxf/vRoyo3vn+DaTJV+cWygRzFFfxmcIHnUWioEyyb7O2dDBI+jMsrVi/ZEITz1a66IbwZgVzLjqjIlYUgWONGA1sDnYd2YIfyQe09DGyX5i/WbzTHLIQHOBwW4UbaH4iA/Fh0NSKyYLW9j1r1vpRgsRZ+rXxnOjM0uag5KfD35g1zL+ZV8f/+kAx3nzWvqyzV0L2dMfA3JKLNM4iv65ZyULOkIEXZqB4VdSruu8xfzjQhR4JZ/4LKULFTfiHQwOsXlvcFKaaBSPzlQbyf3LvaqDrZRXSxY62PRDepcBc6sTvcpe3qb6yafaiC1cQN+pY9XqYpcH8DhG9r2CaFSWUjVieclZdKp57UIJDU2dQ/Ad0pKzlBeDNzZXPfw65o99EFwF6BVAVedC78ObwlekD8GkCcUyC3yguYugmkBb+OrLbMQB7HMl6Vjp5fg=","layer_level":3},{"id":"25c1fc51-6b17-41eb-8829-6f749d16d128","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"布局组件","description":"layout-components","prompt":"深入解析布局组件的架构设计与实现细节。重点阐述MenuAside侧边栏菜单的路由映射逻辑、动态权限控制和展开/收起交互;分析Layout布局容器的响应式设计和嵌套结构;说明ContentLayout内容区域的自适应填充机制。文档化组件的配置参数、插槽使用和主题定制能力。提供多级菜单渲染、权限路由集成和移动端适配的最佳实践。","parent_id":"29fa1aa5-5021-44cf-b284-95390545e925","order":1,"progress_status":"completed","dependent_files":"datavines-ui/src/component/Menu/MenuAside/index.tsx,datavines-ui/src/component/Menu/Layout/index.tsx,datavines-ui/src/component/ContentLayout/index.tsx","gmt_create":"2025-12-25T23:46:32+08:00","gmt_modified":"2025-12-26T02:03:08+08:00","raw_data":"WikiEncrypted:x3LcpLCzT0KOPxd1xeYY3c7iq48qz+WPAPm3x7MWgVl9Ka0y39BYIpkYIXIwXtcEkjLNRqcKoI34Ay7VLfvIoX3xCEZ/h9SOKf8FqMpLpAZlmLFTLq9V3WNZDgr/Vy9dKgEn0mx+KcF0BVca6sW7UVb9HH+JkM8GPoZopPfsMsEs9Bspe9S8QJwubPlvB7AhPUfrCwxuCu0AnQrQUIs9DJG4uMrPG2FITDaN9eL8eGgyU7b47idk6C/MDUGa/ysAMQq59JspL5YR9I00DKtJ7sGK412LV8abFJfvvYBaC5w+suw0SkMm9wktNa0gfcRQC37HPS7gqtgICb3CQN3ZaAwv78+z0BZao5po8BCS5sUMImzmBNvbmIln/aCfFQuZGN6ehOLpkZf1/krdHEaonh6a7hZq7TZw+qqQpi2GtZS2TP/iZLSpeeEvhGtYd/uTH0DQjJlsr8ZtN2U899Z5fV6uS/TF23PDZGXgvWGburKO8Cgs0kuR/i8uyMWDzMC6FhMBWz/swiz3fQK53CypSUMgQYCG9l9LcTaqV0TikYP2QW4uG3kdc8k7zFRkhA24r8nMvx9x4JbZa2+LZyZ3MhnBgDs4sfpdlebdoUr2OXWH39YgzwEHA0ezCVnXsDWgonJUNgazOMf4zkVkYZmVIuuAk+451Ov4makt702zPoAMv636nNhvTPVIH4et7t3avCaJTmCtsejLyO686gOCj9AfGMdPJw+ayoi9yLNG4v9RtmjWP9kDbz6Ewv4SLU/k99EsQSrp+MYJMwLCrqT3OUeFqAjyL8myAJ6qfmmbrh+3EwbeeSqHTqMrl+c4aGXww7iH1c0NYXpgg0BheZgz47j+dldskaQGzokcCeVyQQ8GffbgDati7mgjuGeF69USeVp1dvojT6Ih0QPX2pSjvcIWUmzWPgxIfnCQ2JrZB12PKneLWNbmAkdSAnBnBW5nXAzWspa2hbZkOiOrkvsoq2ULa9uqANdzPKyMCLol65SVHFDQIJL5pJuGA99CEBlgn2921ZQQTKw5IHIeJnzJeQ==","layer_level":3},{"id":"b6920582-174f-424f-a6fc-f9e172a29ac9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Spark Livy配置","description":"spark-livy-configuration","prompt":"开发Spark Livy配置文档,详细说明DataVines中通过Livy提交Spark任务的配置方法。涵盖LivyEngineExecutor的工作机制,Livy服务器连接配置,会话管理,资源调度平台类型设置,以及Livy状态监控。解释如何配置Livy相关的Spark参数,包括程序类型、Spark版本、主类、JAR包路径等。提供Livy配置示例、性能优化建议和故障排查指南,确保用户能够成功通过Livy执行Spark任务。","parent_id":"7bd8d8bf-316b-4e5a-a32f-786067c2d1ba","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java,datavines-engine/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/parameter/LivySparkParameters.java","gmt_create":"2025-12-25T23:46:32+08:00","gmt_modified":"2025-12-26T02:04:05+08:00","raw_data":"WikiEncrypted:M+m5dxh8XuRtgpG2DvE8kuXWw8op5Nakrlj6Uij2A9Uq0k3rRgPrwVdZkO+dWiHWV54h15JoVj6loyfCY0QpjEVepfNeyEmqhZcxNcN0gn8BxM4dxAQS2tKumqEYkcDlGNui6OHtnSb84uBuDhgvPgU8L5cNdOSUhscgWmKw5AqA8seAYGGk6N77JICi8xMWuDnjPkS/+qw+JF2cqi5WIf1ZmEzqMAQonxaHHP+ER4JS60fNrQffO/KpB9MtIOVbjsruyJtsZNzP9hrHuhbnnsAVK/pGR8VI4k3sv9kKd8BDIs1ehI6FtOfzy4ztZhBeAe1dAZq3IdqDGZWBljlfqHYDt+wFWws0mxsY/9ghnx6r/yQAE15TCVIUc6VhYSayivUJWvRx0oi8OltdaRCmQFBBqnIEhbiIqc7hdstK1KK/ewKQsYFjqbhojmwi/6KpHaaP9bbrjdaHEJyI3lVonlEQdNalY0FK3zkrR3vSoujsx71alDWts8HWA4eHO8U0nAHVOmmzCHfArdQY/DlTdLmgEFSiHYUzlgof/KymBcWw9sHMsn29GCMcK6T/06FA0bMxiVvL8Ui65jtsGsPnHColjX5/muAr2eIgzABAMVMJ7fMV4RBqlCW6mAHJyBs37tzODb9rSUSDe2noJNiBAYt81YpR1WRnaqE0ZHVDlQKH463osEQt3UU72Nv4CnXwsE9CcHOL3dvapjPmCwJ+W0VabMEBWUYcitumwSryFjEdTkh89nwHWtwkwyV+DlkTF3C7hJlXcavAZP7tye9EE9ZjdO2DZpLvfdIfmNzR6bFwfftSkD4YJhNE62SSGTDl2sXu9EJW4AMTDaQIch+3dtFx6oD+aZOpyGIlhelVVMjnyHpjS+gyDd3tYo1k8fJppMcBOmWiyiHB/xqsHtP+6pj0v5VguL7K3ARzw8pqt+zob/5u1m5yeJEWaB9gGa9RMbvFsgXUR3xZwGcwpNouBhmxC6H3WQHn3bV957HfHoa9cJi5fXfmDiK3YI5iYaIwpuw7iciYonBjrGeXlZ0T6MCnr/vBekxkSUEeH78cJCers1T1LAn7MTj5o77PJoVrVzAQCYyyoKHuQ2KldIr7a/rwd4dxORoBdso2DFDaGz53TycD/KC9Y+ymHLGNXW7vjRR3JKj61SRWVbb0A5qCy5OlKuVQZIMZ00haUK1DE5GypHs86c3ztHFdHwp8AZvTLdKzNrMTKnlYmytXdPfKS8TrDhrzrqLIn1t3Z7Ns5iwn5jZBJGHugnWehdAkoIybb3lBOET+o+L2gnLzewKX0ijjQ7FU0577fRt8I+EzK8ArWzhK0dBHx0PLS4eoCTw6bKV4phC9DhhmoE4qrJTk2A==","layer_level":3},{"id":"33d4bb84-a5bd-4eba-bbea-aa4e5de209f0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Livy资源配置","description":"livy-resource-configuration","prompt":"开发Livy资源配置文档,详细说明DataVines与Livy服务集成的配置方法。包括Livy服务器地址配置、会话参数设置、资源配额管理、认证机制(Basic Auth、Kerberos)等。解释AbstractLivyEngineExecutor和LivyTaskSubmitHelper如何实现Spark任务在Livy上的提交和状态跟踪。提供Livy资源配置的最佳实践,包括会话超时设置、资源监控和高可用部署方案。","parent_id":"e27cf36e-27dd-4b26-a11a-f8f2af97306c","order":1,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractLivyEngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/helper/LivyTaskSubmitHelper.java","gmt_create":"2025-12-25T23:46:38+08:00","gmt_modified":"2025-12-26T02:03:31+08:00","raw_data":"WikiEncrypted:NsI011X8IfOFAXh3dof0eysHbr5qPYwAN2XrJti4QmesQ0rPfa/I9uF4PXuD9SnpXKeTO8EzDrZx+MWI/2xxtQcDtWx2xe0ey4llFLwHQfqAHWc0KR186f+aGE5O+RfkLdmMpXDKKS9OuKJlExBwXzsn2LrSJmAo97Ty63dENyDhCW/fRAzButHRnjTZmj/SnII49t2KJl6eAWKgf6uRTmO6HXtY/Ye+V7murzPfc4W45yp47LJgC+pbZfcX4oAxran32vitsSKssSwW4ArEgLuHcIaqAtOrSUCTLzXmkwAMdrqIepdJkT8EBFlojz+YlLklOWtPzv0ujK48xyzNmCBuTSeRooAs5woyqaf31ChyT4ODuzhasL8N/HlHUpRLRzF9O5quHwVqBtx8e5EWE4VWbfHgq/+PJBLGNodLU9RpTfYG+VEyLoQV1aJQKDpyGQlzY+8SWg3pmC2OJ7dVWJZAjgD/yJjvgJNsEDtr03E7VWgSsBAqhsxtxLLo06wSKo+8aguaaCRLyl2V5vjMVl5WZUhz+/n7tabrJjlbgFafiSZ3GGuACGopZc8zBqwd1ZHGS0vJMeTISP/UlR7csvVSMw8VMpK1kdaPD1EIKVoQqulMvWyoc5CdYdSJQRRH81VixJ+ou5YDsCfBBeMsFV6GVrEXMUnvwIk8d2Uu1DHNcYCQ6pMQSoyR4DGqYLUPuLLN0XOx1I/ZaYHG4dieGcl+jI2xofIJm0baNFJtFURQLbmPbK5ZQxUcPErKTmnZVP2RsAwy4DZn2PNUcTPnfAYIeyabW7bRMTWaZraBfQC+W67qgWVAC3RrpL+6TQSKz5GatwiDaJJCWsF/1cRP+EmFxB+XZTvSf82rqGwaDj9/wKgUE0MRelphxGo1ze8DSGpu5CLOHfZN/3ia3f4GeQHJCePg4GEiptdUbSf9wAr38ns9h9t1iU/KAS4gK3dBQYQ5bh3o8yNPvnPKdRiR1s0LnWSUmldbuMKaOUfquepF2vlI7GmQSRd0QbnARUnyANHs9Ta7gl74cSadro5r9vRvx+QfWirk9LO12Oy8NDZi0ZFJjQiCMiRaT4CDLiTe5s6T3/AmsL8J4lTkiaddw+Tuj4k/50m1lkpxvdoI7K/RHt0nGbbYUohzanVdp9m1/BnnGBBsQWVTWo7REKzESBD/Yys1j+R+bOGO3DjuB4SeCD54kGsoMalMhWp8T1AREYTp5WgwJa81q/Mmj0AY5w==","layer_level":3},{"id":"d29ef881-2a58-4b10-b394-0120517f7d7b","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Spark配置","description":"spark-configuration","prompt":"创建Spark连接器配置文档,详细说明Spark连接参数配置,包括Master URL、应用名称、执行器内存等核心参数。描述Spark Thrift Server连接配置方法,支持YARN、Standalone、Kubernetes等部署模式。说明Spark SQL方言配置和兼容性设置。提供Spark连接的安全配置选项,如SSL/TLS加密、Kerberos认证等。包含Spark性能调优建议,如动态资源分配、并行度优化等。","parent_id":"860d9985-eb7d-432e-a1d2-69e59ae12cef","order":1,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-spark/src/main/java/io/datavines/connector/plugin/SparkConnectorFactory.java,datavines-connector/datavines-connector-spark/src/main/java/io/datavines/connector/plugin/SparkDialect.java","gmt_create":"2025-12-25T23:46:48+08:00","gmt_modified":"2025-12-26T02:04:44+08:00","raw_data":"WikiEncrypted:M+m5dxh8XuRtgpG2DvE8kumjfswwXL/Jfz4NfbqIEwop3ApmlpY2Rps/aQo+adKbIv/ullF0zI6ztP3R8hJPZeTOY6+7mgVb1vKJhwDloK8uPgps43EHvFvxLd/i3wRzVF7NFOKiUnJ1f8DFPj4r9VK4AFOGfAbFfvcev+76Qxeyzjw/g0lJaEzt7FbJKIXsMWu33ZztyBZLyeZcgFgFDAI5J+1nfo80YUzi7vWPlffV+negZoY95PdQ3XwgQoXqnS5eeEvlbrPd605DAJ1ZRBuHS2LkCQxvv1YYxrJJqzcR1pEZJJBWPFOdZMxtBsastBKgWojyQ5badKjqPHR2oK10MgpS+9yVzMmu3wV/02OKiB+EHR/sgKVgzx9xGG7LOmT3ljt6YZLJ+Mr+QvzGsMAiUp0Aiwewt8TWX/wob2LUtJNcj6IacdKsUUwkML+ULFL8oj61uzwm1P/WAPWiAsse524fHY97mDf521RFDIDtwx+vgx8wo5UlltdKSzbhAI08XzgHK8Z2hE/K7e9J9SJVu0AJVn+MvyxP4ncHTRCmzegA3cchwgrqYY5iWzft+EDk/hY/jzpCzsb8DR56iRLy9d4yagAP0shhHtsRm02Oa1T5Es0E/YHtVyGTxFDIANg5jTv1vHB2VCTce+EE2a7Iz1W9BxTH3WxLKYJzSEVOYEJmM7WLGkQVtuMwlhG+wdCDS6DN1NGOb+jh6y8r+mlQfbICUUiv3G7tMhfLGwQVhiQ+jsaM5/8NdyT1FAVMAvGrRM/Sas302sWYNvHtCPBKZPt5oHYfZKlBsETgQCnGP0aouf/eB4A9DTQE8p9kzgJanoA7rAw175xg0bKNqj3RiZUtApmv8z1FjIaag3iWyXDFAe1eky8YBPZN9u18dAKQpiBT9mPBwf947M4MqnSDgxBCyaofGhQ6CSBIs5CW+bVDWFBf1fGmD0MR10bzMgBjG7/JAg1m/4vOS//4LGRkbF5pzPoBgVTmyo50znFrSS+h1rvXkdUY4I36WpKSnNwL1xI62eV2L0A2i9FbXumisX2dMTAWlmSuW51en1sPLQMpsX7htudYEcte6sv5sHqttCMmAiUi6VCVcLxv8z6QH4NbHLBr8VJzjhWgKMXK4gPo1D+AXalIi6o1JIm5xZ+58F/CFOCZ3NgSy0UEuX8l6/x9pWXA+23M3kwxByI=","layer_level":3},{"id":"e85fa451-84c1-4218-9ff7-9d263c03553b","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"分布式文件系统配置","description":"distributed-file-system-configuration","prompt":"创建分布式文件系统(HDFS)配置文档,详细说明Hadoop配置文件(core-site.xml、hdfs-site.xml)的集成方法、NameNode地址配置、HDFS用户认证、Kerberos安全配置等。解释如何配置HDFS文件路径、文件权限、副本策略等。提供HDFS性能调优建议,如块大小设置、读取缓冲区配置、并发连接数等。包含HDFS连接测试和故障排查指南。","parent_id":"1e6b21d3-ffbf-4413-b2b1-7835661a6c7a","order":1,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveDataSourceClient.java","gmt_create":"2025-12-25T23:46:48+08:00","gmt_modified":"2025-12-26T02:05:34+08:00","raw_data":"WikiEncrypted:YDoRcNsKkN0DDXOHAYnH4IqtG1jF1yRR1NPedG/arQsIwenGemd+7B2re3U8yI4u/xatMLoR8PfqTyEx+ISrmjMhMUUYdrPTtljkTT6jY5KHefqRCDgtBcpHAR0Mi+kj8sARVZ591u3i4+/1BJM73K3JWCR7AAoGds5YYsJCmyu++qsEy1TJSoIoe6xO9xiJsIyyD45DK61EumA+6kFI21LiRi+IcQhh3o5odzvJzDpnxDpOnpL28uwDJLdeOakHltONi2YTuxWuqi58p2pIPCCHvCVlDUkSqqyK8hR7z9A5J5Wsr1beSZvkBv/DcNkQboCzY12SveUFxRdznHs+UK+mcD6460MEvOKVl72Zpe8FY7JE1pqKSFWH2uUhAzZcf0XeqOOxGde5Kpxq0RiwmO1wBJ6KXZmCw6YM0yP23AMQh4jZo5c8M2ITjPFWXGAbItEHIbK1lHIoduSs5i2DCMnCMrnxOeoUrSdMCV4wjjZEujeJRF7Ak1+ABgknhNM3KpZ5RT7qDcnaCD1g8I4gt5N6ckuyaCj2eSpP+e/IRjYRF5x1v/cjPZKzezKaUq6MS4yuSjMJuUf60T/KvybnF282Dk2rKiozaY6i954L3jGzXSS/yrUak+N7FEhGi4KAoKJR5X5ZFOUwaH9chOVlIzTBXW35laYLURlp4baEPUrVbwKU9Ry4LcZqQDAQG5H4eFKD8D2HAJ+Uq+ECklQcGRitn/IUZhO5TpDksMLcpESulyRdUeUALimR6o6ZAXtCIpMqUS9PM10hfM3u9ieVb/XMazm5aXqwLivVXR0BFnG3vZ6IAkG8bNBgMH3x6iY6EUQwIn9OkxhE9dCSGJ5y0wd0acON1wju70c7MF7CCG4Aln6VxESBoEbPZLcfEDBum1R2OBHVhRmWL8FMlpizMJoQEQRCkGniuPKn/IKx5DCS0gl40lInXghi1jVluaLfBp0qXUxpj8DlunQxoEcYvcF7OQVXYwbi+7bI/OEHlwwUmVy+9cl5aCfl/GHu9AmJkkpbmUVwLS65unPyjVNEnGxUks/lNajOHCMLr3MNXmZOJHik7+LRQl3RsgbeiX/HtjO9yqyhWjO0CUWrJCSF1Q==","layer_level":3},{"id":"0bda8e18-09ed-418f-899c-e094cdb2fee2","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"验证码配置","description":"captcha-configuration","prompt":"创建验证码配置文档,详细说明DataVines中Kaptcha验证码的配置和使用方法。解释KaptchaConfig类中的各项配置参数,包括验证码的字体、大小、颜色、干扰线等视觉属性,以及验证码的长度、有效期和存储策略。说明如何在application.yaml中进行相关配置,以及如何在登录接口中集成验证码验证。提供实际配置示例和代码片段,展示自定义验证码样式的实现方法。包含验证码安全性考虑、性能影响评估和常见问题解决方案。","parent_id":"9a060c11-69a3-4a51-9fc7-0561602d8775","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:46:56+08:00","gmt_modified":"2025-12-26T02:06:20+08:00","raw_data":"WikiEncrypted:RRJ4Sgb9pcd1NrpSPsFnicgNYH/Jb9r7pf7KGDQ/VfeAS5XlTLjxf1D/GweynvQYacU/OXWJoi+JILWQTusWrT9liuzG7XHs+k7nl4TnDfXhZnssXEM74NTpLE59igDkoQ0NCz83i2ObqVf5h2vVHl38LLzJvxDOYQecIeuft/JPxwfa/DOp+ceZkHP7a06VYdjmQUuq34xbyh24b3ZwwOObSqH9/Mb9kJauITFC+ywEAPaqelz1rqQAaw1eVLAwE4zT901MRQhnfkfdR1cn/cMoh66FUejEYVJG/usLXQXIsnhPOELMpgr0AW2ccymzlUUEpasqnVPQ8myc1ZtSgC3tOmnDT4px4yn2uha1yvjJmQ1twwGJLMMkeh2yP88l/1pJubUGcZm0S//Uo44qY44DwzUgr/DpEpaRx049WkMcJD+Ek7OIvHYnvANGdT4SjLAsIbbYWd16RksStHPmY2Bqas866hiqgqXkFXS/wypIm4vieOo0dOUbc469esqtRMmUyHBrDNcOtC/2xvEkz1RW2nKMlBgG6FPoJXzshrf+m8kImliHobQvSdJT3sk8kX1ELRubv92CDRDbgUBvTZx0RfQUvVxmWR+pdAAueoKp3NTE3h91vruLLSAchnnLyEMoxyNM9r+5wa74XypReAOxEHmgkJsFpZENOpACqrEPJhzBgWEX0neuLgfTaEFUTgqcCZdUx5nibS7RU5ZJjNF67tIriJ8BTSJcpJHyXNpyDSMcABDS7DzAvglgMKqMVyFr8vtGYNe6Vfe4Mjtsrx9W2vSFEeEhLFCbvtMPmOYPACGxTbNRSY9zJx3fDBxuKoO23lQpBXTrYc06XkMeJ2iZG2RBPpN9XLDxTEJEKyLauZgT6/iJIcpXusYAwCN0KVVBE8f0sU+BO+KoPmcQ80TT4s40/Uy+664LHAXW7aIwBLjArtFovNvE+LqupmZvhgb9QLx3qOT0JM2sqqtNKMUOaiZEAQrpKGTjvNFrJPHF9gRN/hJ0FZfsqHtf7KRjgfn0sARory/FFZ7e9OTByk4LzapJVzIoxGgUepnbfD8xJInX/FBwAWpFTtvODxeG4Fqwp5ESLaRt+R1UWJMDewKZ9mPa3yRjE7P22VQFMcg8BqbB/TtAchIW1T/Dq35Ic+Xb9YqvtM97e8/LAGSdW3uPGS8okMVqDmP/5UZ79sn8/ILWYc2y4VZOlqMgectTcIvi7aCHkSxt5X3X2kXshQ==","layer_level":3},{"id":"8f331b81-615f-484a-9128-da0c76a96189","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"PostgreSQL配置","description":"postgresql-configuration","prompt":"创建PostgreSQL连接器配置文档,详细说明PostgreSQL数据库的配置方法。包括JDBC连接字符串格式(jdbc:postgresql://host:port/database)、连接参数(如ssl、sslmode、currentSchema等)、SSL配置方法、连接池参数设置。解释PostgreSQL特有的配置选项,如模式搜索路径配置、数组类型处理、JSON类型支持等。提供性能调优建议,如连接复用、批量操作、查询超时设置等。说明如何测试PostgreSQL连接器的连通性和性能。","parent_id":"82e5534e-5b78-4582-ba77-8590166e6cd0","order":1,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java,datavines-connector/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java,datavines-connector/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java","gmt_create":"2025-12-25T23:46:58+08:00","gmt_modified":"2025-12-26T02:06:31+08:00","raw_data":"WikiEncrypted:0slJAk0S9iJjTLO9xyEAJm10JC0QCPtLluXpe5u1EHK9Cq3ZMDu9DggNU5fpPRRUJ/xZU4nguBIVfZW7au3l6xXdHmjcNMK3n3n5d/1btPZOBsJ+Qm8Z/j2doll2jEVPpFSc69cTd95dBPjyOR/ZCtXu8awQ6BaYF7uUQ/z7WiaFJN4lk6Jl27hxbgbdqaLfCCC4qRtonFTrRYoZddErgH1sp1V9gNJ5kF5uQAZ3SWAcaypyGuZVsD0Vj64pZJlKlczylftOIZUa66b3zY6d0WGQG2+uWA2PfNNoNCcj5Ra3PkPM5x3JzqzcrK4yykFFRSp8INPLzDut9Dpvo6qkPC7inRuL3e/vDHnl8GKdKYaV9Wc52gnozQYmrQxelXj82oMv2lWIk9ml9n3PC7OfqThwdoa0CqVgZ8g3Kuf3K+UrnyRdL1QbJckMYs/oyqZgvhfPhVjP9Ffz0mCtnII5xW7ThE1s0+iRdg+MmsjSYJjT+iTzmxWpyV77ZXr28W/hbq2ikW0n6hh+RJLT8Y8OiW32Vr3SM2mX2F3MJPkV0+VI7hERG9qbQHNK2i0gqGKkZR5aWCC0hrsdIvNU0U2ozkjyZX++CS+vFKMnCO9FDD3UBteFRwn0X8mOwEPPdnBzT8M7kjlyvKKe4isQM8HhmOUP4v3VWGqev3/5ejoRGTxyMMyN/JoPeDiYIp9nCFgoGWc2CDnKccSC+p9Z/DUcFy4LgtlCZMjFtaxMTqEOzO2QKIBZc83k2e1Iq9KfkPEogQg8rs+v3khiZpd46edgl4NJ89cDl14zDwmDPUkXa/G/AHyUfsbyQhhAXC2sjqVo2xiqrl3Gsb34OWtu5xcIPhiM0Mq63QaUHP1Pahoe+ZHJ7re5YwoH7M0PmvBfFCmcFehHQOhBS/+DIW2Kq0/swHkjyMF2naNfglbfmmO9eNDmC+tFJq124pmF6beSEvEUIWqsP72i8LmTLufGMA08Jqw2Rwa/8g5icwvmke2n4aW79G6paEtwCnMhM2ZQNzhaGE4TJarich8MTDcURh8DJ2gDJaeJFvnCOMFFCbmN6/N01qeHOx7OGJjd6HcWECZFfbGy1rhFTU1EnOx/8Czm+NpU8el2X+eElF5Vk23IpMI+/pEyRQ4SsXDSFPa69vyUP+JPGlias/i1p2qwsC0Ks44i4xWhdh1J6xKMjc2jULGsjzigncCJBtQcyi1JsJCoVt5pEY5CI+5GrYvwYQcm84CBg3tuue2pHY+hsVU06oxZd7eEjp2X/ZWXlC86b8bgPvunkHsnJjB+xzPgd9KmzFlTfK871BjNj+7mWUbU+6duJIBxRBoNkY9Cy9hhfSLAy7XqJmFi4ZXtXy5aKew3/h8Pmt+shVcVl74McpOfe40h8aDYESGQFA74oaaGwQf+mSPqvjgQUGocN+RfnEroLl0pD0kGgwKHHEunawSs+nWo3bsKSen7RtvnEaYbFTTu","layer_level":3},{"id":"71ac64cb-e9b4-449e-a217-d00b31969fc9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"权限模型","description":"permission-model","prompt":"创建权限模型文档,深入解析DataVines的用户权限体系。详细描述用户、租户和工作空间之间的层级关系和权限继承机制。解释角色基础的访问控制(RBAC)模型如何实现,包括用户角色定义、权限分配和工作空间隔离策略。说明多租户环境下的数据隔离实现方式,以及用户在不同工作空间间的权限切换机制。提供配置示例展示如何通过application.yaml配置默认权限策略,如何管理用户角色和权限组。包含权限模型的扩展性设计和未来可能的权限精细化控制方向。","parent_id":"06284609-845c-441c-a8c3-f5d5dd0354e9","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/entity/User.java,datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/UserServiceImpl.java,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:46:59+08:00","gmt_modified":"2025-12-26T02:07:00+08:00","raw_data":"WikiEncrypted:arCjhUL6OOP3tq0tMlrtoGWKRBIvi7rHtyPq7aShmQFlJ+fgWJ/Ok+snxrmMqOmy1cnt7FomCGCB6A5WJW1OM8jUMcnsXwhYviXg6nx92es8zf3lwNn0W1ZCgYDgLHT7odYvCpN6GQbuZ85dX7WIW0LHlOD1nQbpxWAGvr5TZ4EpIF/1AGlXT3yNOZptVY8MCSwkdz1RdPHJAh8DGh8ssSIpHhcA+PbevTDtMDDEVDyIcIg779EwKTi48Fb/12GMSdhunBQ8zhrtq/w0Q82eQOld+Yc5lmrtGO06WTzKeMIlOm0GX1LPfVkkocjQeWYPiF6vyh58YJXyD4ZMtq+4H7o7lhL4cB9Iur8gVixMW5zMGOC1voe10xHKR4KpTdjp9NpI1mEG8sEoA3SMdk24wZwziyOxYmnl9CFDgYTC0PC77g+a9m0SkiqqgbUF4Fqe++H526DnbwDN8w9QMrSPxqN9lTRVVnAkOajYMSYwn5u8QPwNBeKLlO4tQE8EstjiNqZKt7txkDXUnylnKs45tMJEdWABMfSy5goLK2+xIVz8ViukMsG0Ht1SDRefJ7u/HNE+0e2zETjI2PFt1C2aAt8c1nCuQGLosFTpeadSYVDdZsvX0ttAb2FUoR8qAglAzMx8P6MbpddXAtJwiP7wWy3eGXDZlrPHFCXC9iugZkmh0ZLqUO1BSnzQWYgfmGRU8DEMUQlSv7WTfQB/L2MVyZ+aDGBkACvWsNa53kCJ6qWee9INpYpH+WmE2+XxDj75enBJ5rJkB/PS59WysbQqfuHOHI9/qxsp+/J5Z4coaxxlQRrJUauYYPdpGNdpc2QjP5juCHPEogPj0iayaI+rmwtyU/3RfQbtFlx5lDAuXmlD6r2W15I9mqWLWwGuDyADco9TodfaZxTJm0ZQyPsVSqzqno7CRmJ+9kNx/eMJgW+RYmG/MSLPiZaXAIkOcg0Wof+NmjTf3lv3BGNME1E1oAtps0ZjXRLWR6rRtauqpiaylTZt5fqGNVSQhcRXWZZWH6/V0M9bk2yNnvtusbbsyurafLEojA/jJu5oHn4emDpP8JGiYP61gAPZtmXXSCotT3OHmivySZ5wOGjmjdTMZwmfbQsM/JfiSeJ5BAnw0+hEDi5ljopPDiIIP0O8ZL62OMKemrSXeAj78Sd5e722acxZCJW9Fc4ga1XK5y4rBrrWaY9xoHJMQS1Cc6pki3LGEubgYHBLtnysKPORZbWikZxd21SJdJ+oR6fu8UpeCM3dwbtq5bYME2/8dtvOwSx9XHjY0qm59LG4TimHD206a4IfUoY1FSiaa45+WyG5zlqf+ABjJEqilrHmo8HzOBSnkbrF7ODzcZR+gniSvIQZiVcc7Pz4CocefbdV1HZrtCifSsvqQeZiR1YtOEqf8UTn7RsDLwFBrs0Hf8TUlzhmdMfVPXaVT9ZuhULTTyUV/YSRe49lg2c5iMTN5cLKKLm3Qkk5YYmJexCpbo4WXwqYZTVB9dBzdwBFYuCY+C1fwkAINm27b9EmX+kzL7gqbPSG0SMhyzcp/oP72XU8L7mtwA==","layer_level":3},{"id":"f4818220-af24-457c-b8d1-d03fc03f455c","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"日志安全","description":"log-security","prompt":"创建日志安全文档,详细说明DataVines的日志保护机制。重点介绍PasswordFilterUtils如何过滤和验证密码等敏感信息,以及SensitiveDataConverter如何在日志输出时进行数据脱敏。解释如何配置敏感字段的识别规则和过滤策略,包括正则表达式匹配和字段名匹配。提供配置示例展示如何设置日志脱敏级别和敏感字段列表。讨论日志安全的最佳实践,包括审计日志的保护和日志访问控制。","parent_id":"6f1fa09a-2cd2-4016-8fe9-896c74cea65f","order":1,"progress_status":"completed","dependent_files":"datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java,datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:47:04+08:00","gmt_modified":"2025-12-26T02:07:27+08:00","raw_data":"WikiEncrypted:ryZ3C1e8/90WRVptjNGEtJXm2jKVVkRKjA5fz8altUHHbTpRBHpG2hM7Xhovg3Z02p6/CjNOEjQEPLoU3/GEFZNcMPCk9i3G2CyNWb+2M3mTEYd2oRTLWnAiI+4hk/gsw0G90NWITYRjn7d8HjpYvy54vfd/Cl858OywUKMr/uMCqDVPd5/nvf7sAAMgGASB26FRXhU56PSGB4RR3+EHDddirXkUSzkGljZHqQQzlX1c1ZGy9rW5xjFgpjCUU6kNoSThUR91zyzVKD7LfQ0L7ZgAvrZGwttD/KsCpn4nqzMiNe1Je2Ztjn6KHxfJ8hgQc7tcOz0/7G6MmhyiPGedGw6Pmtp5gqDKQoi1Frsyk/4FAgzYapq2scn+MEqJyWAG9vOLqc8a4JZjWLq6cu0uaHIxUFiVH/a4rBkNUCcHapvnG85GYbbm476wWrgcAW4rnSckoCBug2ILpLCnHFtBsFgi/jEh6Rf9OlgUnZeWpupQz6yqqOV0ZRs5HCMs5IHESjATffzD3eHLqcgGFygGNMCU7Jwx9jFNbY/lMwPBj5/YfqUYye5a0LX1hyqdmNBQp7oZDnyRPCj6gBcL+TH39OKX1vl8PDRkw8AP8TIY5JSHFlLz8byGIhBGE9mQhNHazuFfCl7kIn6hcsuBgRzBCdHdYnhdngf0BTb631KtdFpW2qna08y9C5ThCulD/O/shlyUSJJvBBSXMlkeSBap5WJOxQrGuWVV0yIEH5STRFCHsRv8Bx6suvVRzHAZ+td1PW3zIldoAsL40GfHkBWYKYSrT7zbKuFVZ7Fh2x88lsECAN4/45PyVFEXLFfEG3Mvjt7MIEmILtWFTc5T4dmqS/DuhANxX3lp2jram4O6BlnDGQLnUttp4kPW5n8fyx/mPoMbxENs72nKYs1Yhc5113j6SP6oQc7mKu45o+/dqIBa8YTflkARqTZBhyu4/pxjG4zpZu4pk/bs+1tJI2+V4hmwQbeJyHrSF6UUNC4F9u1dlHtfJMceLaon8jmZXw0bQxZDwubFtQBzTkWFE/Fdi9kcYm3fQmCTTv/O4JC/jCQGd+ChCcfFCRuQnXL0yngi5NW8MPoBv5+TaytEsbIomdNeqa34v1z2zPQK5rThiM8Vo5nR1uAfcH+92pelVIYMXLQ3CjKcdqJsIoJkDHySBeA6Hr91cQN6qmCgm3wDQC9xTRn16En3f60oCQNjZMb2TXQbzUQBavs0etSyYeb+Sh1Myj4HfMWWag9cLGrfD3w=","layer_level":3},{"id":"7365a2cc-1450-46cd-931f-34fcf055a743","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"响应结果转换","description":"response-conversion","prompt":"深入解析DataVines的响应结果转换机制。重点描述ResponseConverter接口如何将不同数据源的原始查询结果统一转换为标准的ResultListWithColumns格式,包括列元数据提取、数据类型映射和分页处理策略。分析JdbcResponseConverter对ResultSet的迭代处理逻辑,以及MongoDB等NoSQL数据源的特殊转换规则。说明转换过程中对大数据量结果集的流式处理优化,以及对NULL值、特殊字符等边界情况的处理方案。通过具体实现代码展示转换器的扩展性和可配置性。","parent_id":"8686fc3b-bec7-4b41-ae35-31b1eaca7987","order":1,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ResponseConverter.java,datavines-connector/datavines-connector-plugins/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcResponseConverter.java","gmt_create":"2025-12-25T23:47:10+08:00","gmt_modified":"2025-12-26T02:35:46+08:00","raw_data":"WikiEncrypted:hjmMKQe6U1Jb6Cx3gbGDIPtgAH17gNZU5K7HrMjdKCnCjbeYxN1POsTLtK159ZZn16UhPm3cIWNAQGz50lJQw0YjF+fQi4+WmIGMngggfrufe6O8/+NI7599/pNzq8FvJ5IUPUVijX6a5kHPlGB5M23mSKPlLQjvjS3/ZMFWWBFLUL9tun3cJzJFOs7HAgT6OKoZDwG/6OpBtKdg4UpK1CqAMhfN7x5VE7ofxfQBo5ECTishHkTL/IMHzPP4k3nkziVUelnMrZgyEdM8LxJMwD78KR0rK+zaszW3acFN6fllPW0FXcTZ2Z3YYsHNfsNyqVifV2bAY+jnBDrz09m5TYnwiqiLb1bxrUb+6RyfILbuuuA2yS08Dd78Ull0C6bm+5g/gdNh6lqn0X0bh6mdKw2HRl5BbR15D+yvR1TjZJM3WY9oqp55vTz8VgJBeokwQi/NrqG85YKUqryOK40y3K2K514/GikNiqIyb15qF1unlyCj6Kezt0wZ52i1wl2Kuct4GfzYytTrDT7SXE5k5YRA37PVU7BBgs5Ujn5lFMtYkgm0tERbBgHtPp0Paq+rIW3COBnP4kN+IFJ2YUY2H898ELNdt37DXmf/PZlgz3DWf/MGwqc2hyA9D5b0oEaXDCnL8FBXG7BeLbK/DhzgPe2xNRBZ+ZefkvrRqpl91/zW8969ydnbpXIpq24TDVwLk8uHf9ygcQtWg4v40QFAWjcjFuh5U6d1TPhz18jTbV+Xbk8pWYSD97xqFrOImnAQ90k5MgssoNjVSTowHuBx1yEHIzvzrwerjykVcJ+ZAuoEErEMPX7jJ3PHLfU3llud7SE/XAd1kaD2rXkPj5+psfS/v3BIrDFFmPOshwlGaSTWOq4uifdCDchk+Qi5+YBCTG2uLgPaiFewclrv1yJ0RqkdZisGDALRSyOPsLXigsWz+wbt3fJV3gFgkwBLibmMKYJSNPQzyZLcf25haSmA76aQ6gKnxQU+JfWTx47S0AQcXqAyOnN77qyGqi93Dqfkp1vL3gQtUIxXl3AJ+Z24qgVnwuim5QDK6T5hgBERlQW5zjIqC3XXF+FnHGPxSUuhN6XlAJ7KaDejcdmCg9TyLNmnWSdMvcCJFJDvTUsqQNc1aQFoj7sILjTT3I3q1e7yfmNkuX2Sm0Jv/YJYsD3tvIapoYnBYTpQP56dws6C0fLnc14Dm70PPr9kUbW7jOFPuNIFpYK4mzZi2i41yupuK8h1v2rbJdKp5NEhssjYrPtpkXDxcqn13QVlVThrsUQNyD9bvShjwT/S8hwv6h5QQoTBWENeGgwUV+tqAUPSrDjPVFhpJWurZJy7GtThbl90mgOQrE4TSG53BGZZpdGiFG1Nv5gOffY15Ir7UeKho1sRvThCIwDsCoTh/+stXMJ2V9lW4jx9yebtAfcLnkPxYwo+DYGh3g2CgjH5MKT9djM=","layer_level":4},{"id":"fe71d112-2892-4cfb-a3fe-29e5f6327941","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"命令分发机制","description":"command-distribution","prompt":"详细阐述DataVines的命令分发流程。从Quartz调度器触发DataQualityScheduleJob开始,描述定时任务如何生成JobExecuteResponseCommand命令对象,并通过CommandService持久化到数据库。解释JobExecuteManager如何管理任务执行上下文,包括命令的缓存、状态跟踪和重试机制。分析CommandCategory和CommandType枚举在命令分类中的作用,以及CommandContext如何封装完整的执行环境信息。通过时序图展示从调度触发到命令生成的完整流程。","parent_id":"bfcfc439-ddb2-439a-b44b-cc168804d1c9","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java,datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java","gmt_create":"2025-12-25T23:47:12+08:00","gmt_modified":"2025-12-26T02:36:36+08:00","raw_data":"WikiEncrypted:+fyGQgd0eREU0LbdYoq+mBFzCyemmlqf2NYvCsh5iZILyAOGz9xqIZRf17Pk2ytvgCfEBh4sXNJgoMqeIbinBdBJYs54njtbcu3/9DqyNnylL156ZAFVbA6Nvg1k5/KYwx/7d/Uo/SUFTO+B+XZOlV7NLdN8J98SP9yUGNQR8yM7DfWdPJLD4R/mdxwrBM3hBnQSjm0WKTDDXJ3divIgM6ZZfN492AdPXmKvk6lWs6A/ldH3sYuwgJJwksb1Wj31au4rSzyDXt+Pj6QW+2kAvNaYHpW3Sq3GRfQ/b6KHJL6h7Q8K6q3m42cPPbvRId4LxajAZZjSFkNU9C8+xkoPtgd1nhMOgolH01cFh0NIJDemyOw3HNhTzx8h59+GDE8I/SWjGNMrag1ObCizKARYsRVWluCydH03az9sDv6pvz88pKJZOon9ixqLqsJWDcuQMcogjQG1vewuW0TQPbq53Uu3hAnmQZgmzr7I9sXdzRvZ5sjh1pPY14Khi+l5DXonHR4JZjwMyOYAnBWRQE9xD6aMZQmgHGVl624j5tllMNxgDA4DyYihOh0AsKDbCeUtm2g64jQOXzETZ8imD//HRgaQr9BNS65zc48etpgLJpmY7OzCKN9VJfFc13XoMB9+93ikOZP3KcoBWvSdm2JT5ak0k5vfcQ3FhhT0YWgYpUtURVr6rKod+uxdy3s5Qxtbh+zSid9fYAzARFmZ1fNIBkpsFHj4fD9EjF00Iz9VSY4dXptAJ1oRpmCur1eOdk2KXVWtl7XORLXZLq08yVGTgIGbdv6kV7p2tsah1n2eguM9w4Grubu5Krd01mWa8FB7X8oT59wgUWlDZiDotwu89IerLN/eX8TKLi6ZBlmDxgSuxZvk6llSIvfzpc+7wlCisNEPLtTIeTSX6tKt6WdMY8jZcg+cLPVCAD+rFCPKjXI5dVOAFQNNx1PcjsyZeMnwkj4UTWYG5iOQMJiOyyQ/UMY4r7PU25q44m+xv4qdmxIi0iaNpiRWkNQ/rVvDXyVRlb/+ADXku+bSu1d2aSAmbHvwv6Y4p0ipu6CCRxXQvhyaRL6oUeZZSBN7TyRpb25F6Be1fWsfHlemfjgCERi9dddo2Df81N+iqnHqwg+FcIiwiqMgjoJlwVVAMhPWjiLsKzgPfOlYH6cwW/wJwpGUGmRsbjOiIfTaDx2DhmtIxqVb3xkuP8EPUot5tu9upKuh447KbK9XoR6smljtulOv0ftH7F3j8C77PtKTZgA/cYsojXZ76UjDKeRZItHeSLjRAMLE+CgRpDXo+7AfZ81uRJgFdcK50AUKe2gp91EcjL/v3azR66bKe+DVlvK4URztxvYRJKaJ4KcJNkWONC7X0ksJPseevOuHJG68A997ECNXJKw80X+n+GGE6qqI09fXvCXd+yxo5N9xtsXxpuV4vQ==","layer_level":4},{"id":"945bb726-f31e-4e2d-98c1-70c28d3af058","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"两表值比较检查","description":"two-table-value-comparison","prompt":"开发两表值比较检查(MultiTableValueComparison)的详细文档,重点描述其在DataVines中的实现机制和使用方法。解释该规则如何验证两个不同表中具有相同业务含义的字段在数值上的一致性,如源系统和目标系统中的金额字段。详细说明配置参数,包括两个表的连接信息、用于比较的字段选择、容差阈值设置(允许的数值差异范围)等。提供实际的配置示例和使用场景,如ETL过程中的数据转换验证、不同业务系统间关键指标的核对等。分析其实现原理,包括数据抽取、字段映射、数值计算和差异判断等步骤。讨论性能优化策略,如如何通过时间范围过滤减少数据量、如何处理大规模数据的增量比对等。说明在执行过程中可能遇到的常见问题及其解决方案,如单位不一致、汇率换算、四舍五入误差等。","parent_id":"8a7821e9-9176-4c43-ae8a-64769c6958b2","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableValueComparison.java","gmt_create":"2025-12-25T23:47:21+08:00","gmt_modified":"2025-12-26T02:37:13+08:00","raw_data":"WikiEncrypted:aGZm3JQWToe9L/Tzqw5CVkYIKTsewQFg16Xqrqc/T2c0pIKJn67nSjJ95hXh39g4rLBVx/lkVgY9Q9ZBa4vqO0fHt5MsZTd/YwCjsMDwB7CovKnUz3lrm7OSFYX92BpDNJLn8XI3tdIYfepKcXFsef1KUPJ45ZttIB90xznWoGm7gl2SqMODfJ0lvKKeIF/3WRLi8Xiuv66wnNq2GSl8z64jOc99rIYOFIbAR1anADf9lG4GnuswyPTJV+4aEMdTqhbVX7/OtdkGVCkZQFTRlX1VJ/3GbqbvDXgXzMhtMr5Wia1eK75GAd3tzMGjJOmjQgkDAY9SLl8W4I7UVljXAXoZFiuzVUii7+qAGAg8Ysk01C3bGyvbJnHcJKVe2HVJfLorBgO5Va6A3xkYAXf7Ir8zaRceQduTeXJfVuHIInHkPPP+JLAqfxhg1fHZvrWa0KFvewOuMILJx7O1y0RqcxC5CA6EUy+cZPfuJj+Vim0DDn/ZhpASHEtNh1w2AB90AopRL8L/+6/VjnkR/a5PXQ10qFYjXSVZDvzJZdUJiDRgwrWT2cVOd3rsT/m1zYvBzw6w0jF+8ReeGSdZYRv8WS6DRguBOVpNHrb7CY/sn+hdWW/5DQHA7rIzHfdedj133MsWMXzcT3FZawjw+hAp/yM62ixKaVZV9avlZ4qVB9eo2WSlJZ6UIYLhZaQbNj1Q6boSuEUFZGSzu86N2uI/fdaLxT0mhJVaJHRivtxq8HuLSHfugPBbP3HyORtZP4rIZ2vlSmHQf6CpByWuqDgAebw44EkiLUtnjpNtmIMHxL/jykeHkxwzPrnh6/2iXwxm+Mj7wkp54YyMZLI5DAPOnw3y8DhdZd9iGCBUVd/j/H0cI5yXkMoRNeZgYe5V+eyUA/1s3OMb2LcDG3S79+A13qQf4zKmwr4mATK5+3vcQmT6I8LvHq8WCk7uNfu5r+3naRXPOGefWovyEbCfmNN9llaUquwORsSlfsyQ49nSsY1MZ7DMFiwKBhA8eheNqAQeHGI2RAVinRwJowetjImc2FMfYZVCzMl8XvKrumnnx4i3KyCWra5qQPwRsPdocDxcu7DH9hTmHqjHidFk8VIy2NYttd30kob570jaZHLsMJlFBv1zOX9yvx8xm63n3EfE24TmaTKOSNRZOttGZbsFfXsHxiXwJx0ij1ZPCfm+m8ZL1RwKNrJYPcC2wrGtr8slovc26BdA9CnhllqEjC7tpxDWs6v9Vejj4b3ulM3dIoFOXO8xmgS3moBnVkfNbASMO7Ykhttq8/BgCVKC7SKQvc/wMqZlWsRgb5zbaPA/KZivYcYb+iTX8zTe4ckRnow+hdHLcGaJxOXVpSqZ7rgOu2M8u40p2L0Cp0jBOoEVHF+gCaNCtGWbyY0aOkSnfYVI9ITY1YSvmso5/zADBaTJ87Aq0WkyeYEtfi0ZheIMH3tCGtHLWIO1vYFia56TqTxuQB2ICWLm5kRIVanvnYjX02fYjKD89MOKV9i/MzCnzb3jwbUFbzHgTUJ4qa1ejVIf0/+rxOKDWRJT1K2WGmxYTe6ygFFjqvI/Ppuvw0uzzF+z87O2XLEydIkHgsofa1Xa7sZKsxOmLKlwc/NdwjvdWUBohvDCzXkZHERLpL2taRRbnILnXc5G4B7+fWGaGEpRfoP/NyJJLoxjJR54KWFcVr7/kDb648D+Y4+MVsctXtI=","layer_level":4},{"id":"b86c636d-d0ec-4620-8685-e1cb0a98cbb2","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"状态消息通信","description":"message-communication","prompt":"详细解析状态同步的消息通信机制。阐述JobExecuteResponseCommand和JobExecuteAckCommand的设计原理,包括消息序列化格式、版本控制和校验机制。说明Engine执行器如何通过AbstractEngineExecutor基类实现标准化的状态上报接口,以及Server端如何处理乱序消息和重复消息。通过实际通信序列图展示从任务提交到完成的完整消息交互流程。","parent_id":"b282f234-c03a-42ab-a5ba-d212befebae0","order":1,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java,datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteAckCommand.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractEngineExecutor.java","gmt_create":"2025-12-25T23:47:21+08:00","gmt_modified":"2025-12-26T02:37:50+08:00","raw_data":"WikiEncrypted:IaaHBhg4aKVK2Z27STIpf6cdnJxxLAckc7tNRHTsFYV17LAr9PTcZ58LDEOPsnxn8tlT1xaccRH2SwBDi2Ta5BozdnLbNYe0vj/VXbg0DQSlZ5mTTXIHhsslUkITyyAvQ/zQzDDd5qqzHEme976+maTXBDmntM+cviUNU7sXtKLkgqjhZb6r70EBRdyOdOLYg9I3MnRS9G8QJaR/Bun/3eHldnIw1ZNftPaomX78M1MRvv7+7QmM6Im/0acGeqTZs2TiLsEFDlJHm9xajjYcwSDjdxN+e8tifo0L3W9m/+ua4i023y0Lgg4DT/kUcB/nDCYQOdjSKpuVwwhTkQz00rpampPIF1vxi9X7g73/LLqhRjPrmM6Ss7AkFUwDPlJ7kVbTOjpHQbdPE8wUgkbJiGNbveQKywuLNTnBOj4Rdq9mFUCjmVXfIL4OAaYVFBIOfBnfUXhmYueAe4zW4ULDzF10WW+7t7YVAuH+ctqC2XPfg2Bugg3vxY/fDPO9PiU1TBuyKzkXScn7VAQrh9MrlM9RvcCkmN3e7ktOa0Gbow/aTrhGwRt5116bIOXZIcodtqaMw0v/hVkZHQdzAExXD7T5IyM1UY95v538rYjJRxOs2hoaktZlbK2EIIo4nLh+cqPZJYy1hYeNCU6uT/eVE+8H8dn34taTN9Ayb+CHhj4rfa+FkEN9ESxBERpX/7Due4ifYOLjDC1LC5DSunnTg1DVdO5wZLyO7SEKxZksdI8mXOEZKQWmp42bpDXbZ4XnOPpAKrDGuaT8eheJiRFdPCKtGken8tpGU5TGadIO0LwEwXhSOIqSPIHywJQgrMFe2NW+Ryw9EsI6ZL7/6hlVe3bb2gi92jrYvvNcgyk9O9dZGNhp97ZCyqswi572rV6W9RfGIoCPNhXTIaXhXdEy7AIxPAN/RZX72ShBOBLcSBXX6UFQqcdt/46BiT2Z1ZLlaX+MZkK86RE6dqBxlju9sDh16eiEcWcCadNduk0Gz3pWzi1SrcZfuEpEQvX+l+2IjHFBu515CoKRHoc5Dj909WlZbcUXyhywYRZGBeYmpSeYY1w/bvsqInha3utE3QbMfoWJsBahREUO2gn8oYZMtEhsoqgd2JoIVmJJKYhZQpZ9XsbXwgbuyGOaAclKbXS4rxEOOnfwq8e8XGqx6dr92otoE0TNftDtkJmzjK0vLuxwN/rKkpskng0K9Ab7nBcjAmzAPLo5Xd+gpXb8ak1scDpZurQMS+IGazU/YjcUFoUDpsWRrGAkI0EYRnYvWw3/lRf4My7ddD8sY+LZagpghgFlNV9GmCt4o2aLTzy4mzE=","layer_level":4},{"id":"85518fd2-a28a-4b69-8ecc-ff43752cac85","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"统计特征检查","description":"statistical-characteristics-checks","prompt":"开发统计特征检查文档,详细描述DataVines支持的单表列统计特征质量检查规则。重点说明平均长度检查(ColumnAvgLength)分析文本字段的平均长度趋势、标准差检查(ColumnStdDev)衡量数值字段的离散程度、方差检查(ColumnVariance)评估数据波动性。为每种规则提供具体的配置参数说明、使用场景示例和性能优化建议。解释这些统计指标如何通过SQL聚合函数计算,并与预期值插件(如固定值、历史平均值)结合进行趋势监控。提供实际业务场景中的应用案例,如监控用户评论平均长度变化、检测交易金额的异常波动等。","parent_id":"0119e5f6-79b0-4d58-813a-14a0a719454e","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnAvgLength.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnStdDev.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnVariance.java","gmt_create":"2025-12-25T23:47:22+08:00","gmt_modified":"2025-12-26T02:38:30+08:00","raw_data":"WikiEncrypted:pYjAeNwRencjUB2+jbOeaqqlke6gC/NErrkytVvJjD+4Z+ISIi2g2ada8xNAMWJ3Dgkljuto7z93wjrtqfIR0bmJbiUMfpNBTlx0XtfaJKIO23sGWUetvZLFg4vmMk0kl4TCcmqMlJaG4DNqCVpKJE/jcvEEe9OlcSYVZedjWU7udQpBllusV4u8miizIEzidzxEsyQ7YgpcHugBP8H3ncWGPFNGjnsiWEjFTu2sTbZSHXIaJYld3Zx6t7cdkmlF/1WBUaV2aOKQRRBHeZ8kkIlr11fgGzcrXjjPXHYDH573J8bmnEIo2R8NKUEyVyibMiprgUAys92lEZeuFIvEeatEVNUY4+shKBMY+k++naee1wVLSUiMmvCuKf98PIa/sDraw0lravklCE3dFfxHHQU2H6FBBN9mjrOj0SaYCpkI7k8rGp6EAd5ZoLj7c53hlgTB6Ip19z7bTlq/DByokpYd9hQpUe5S2aYxxZHniQrKoUcwj5GPXO569mk5tGt6ibVAJhrlPDndTTQyVVBnpf/sPYK8Oavn71ltL/GtqAGA1tXyX8aIB7ZY8ZBktR5OF4h962YCNnjCMaRwcZNQ4+c3+6TWIMQ5iTQKajHolpr8mhiE2eThSc2Y5xllN55hLckiXW9d+Xp5ab8d/YsMuVgmHMX2fY0UV1Vp3bKnOhD2E/JtctJz29aFMHPm0ZceHXMLRhSMQA2Thn5DoE9fcedPJOVMlsFbY5IWPpjdE33dD1LPcpbNrLxGWSU8zlZgezLhI/Q5XxqSEXt6LMgY1aMvC+ux/lCPwGqT517jMp5vzF2dIIwjIsR0cH33XgYkmt5luOLnqqO90rhG4nSOnmWWYSrK50ijgcf080XcuFIrNl8hOqEbWuiM0dc0emw4V7R//DFSRpq5JeGYM81TFoDt5mpj+fvIF8TfIDZfU0PsXY9ZE8kPs9h+m3K5CMt58SDGq2sGO4x/Hm2mHjMf4vWLEgLFJMycIgDlEA/IGsI0nmLAGNXoT5vyB7Gxao6E3PuIr7TH+xEL36TTDwMguvErkVLZEBZ0XegB+hI8VRhpsxD2oWaUDTQ+7vYYyzLpJuHaiDp0AeKaXG8kKPnrJB/Nc6y6/8bmi/OAVPiPWA+Ps/5xLHzyd1IEpXAW9Lixyk/x6sxekPOwiscutqgJQ83+vaf2xpWQch8MJ1gzfc7zwbq3UbT0Zzqj85VuK5AdUu/vb8JGMtrVszv+g/0yNUlnntZl7FPEQQ0aIy2Q9qOP9WZF50l/10bVrd5CVdn7Ho0c0FRTgMRL4dEgaNFcPp8T0g54yuy0sKmf8bv6yEfC1oY9CMsw4mae7fKjpDukQYhQ+7VmX9Pjt8NfwLDIvjKyVdAaAN1wjAQmRxi+lJ0CP8R1bMSYQhJEaVTdsI4AhhUMbHJA8qVXixqxG1adU00g5AxDiMVxs52h3s64rsD2aH3jBOhtRUwM/r5RJepwESvPkebZcMe9cQWuXXsSQDXGtqP0PD1EIVW/+tUNRhXd46domq0uEAOrsBXvPyq7tgymgw8ZlIQmQZD3o8p/zLKx6fjQCdiLkxPjrwy04BQJ6YxzcB3oq/KTWnlm8O6o/zeovIwkw4iuUwF7KX+x3J5RxzluyvtU1M2TVNS0IaUuOdGeMKEISMYoeDpdCyntbmzDhSQZO1og4JqG2krtYQ==","layer_level":4},{"id":"2e5e0a8b-fcca-44c4-869b-60a9720e3449","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"两表值比较检查","description":"two-table-value-comparison","prompt":"开发两表值比较检查的详细文档。说明该规则用于比较两个表中特定字段数值差异的业务场景。详细描述配置参数,包括源表字段、目标表字段、比较运算符和阈值设置。分析MultiTableValueComparison类的执行逻辑和数据验证流程。提供实际使用案例和常见问题解决方案。","parent_id":"03c2fc14-d1f4-4beb-a517-abf842d366e4","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/MultiTableValueComparison.java","gmt_create":"2025-12-25T23:47:27+08:00","gmt_modified":"2025-12-26T08:11:30+08:00","raw_data":"WikiEncrypted:aGZm3JQWToe9L/Tzqw5CVkYIKTsewQFg16Xqrqc/T2c0pIKJn67nSjJ95hXh39g4rLBVx/lkVgY9Q9ZBa4vqO0fHt5MsZTd/YwCjsMDwB7CovKnUz3lrm7OSFYX92BpDNJLn8XI3tdIYfepKcXFsef1KUPJ45ZttIB90xznWoGm7gl2SqMODfJ0lvKKeIF/3WRLi8Xiuv66wnNq2GSl8z64jOc99rIYOFIbAR1anADf9lG4GnuswyPTJV+4aEMdTqhbVX7/OtdkGVCkZQFTRlX1VJ/3GbqbvDXgXzMhtMr5Wia1eK75GAd3tzMGjJOmjZVcuirnsKmb7cT3y2CnApr3SEH3u6CgSsAPHBxV/976h9TNhjPQHNj9xV8H0Ldg0n8qUFZelzjEZBqX7DVYVhDHw2YYFyZ55U1yCn99a1eYnvWFHYzvWzIaT7GKrYoMt050ou5eOqNA1l209V9tvKzQ6B0OvhJ4c9mpSzcZf1MHj6I7fR0JsCXASd8Fp/BjaUqArjBsH6AXnZ+A//sx48bE9WX7wyDEnZXbM42rHHLSEzdXl1DRcg6UphXcfH/IZzpOVHUW1fRzQQLS8K6wPBpLM7QwZxvxnF6djm7N2yg24gGA01iRuF8Cjo73K1Crg87WelBtAS2HR9dYtLBCL68nBTKDDHVaIgDIAflqoKODPMFfgPvduRvm1Y6UW8ekVJkqNO48v8Jh9/ZYIreQVxyWH+7cNIqgmo7vV5bdWN5Ay4amJljwGbp7oa3WmRHjWtjIP0cofRv9Ie+rn0Qd6DdgoieyRhL8k9f4aQIvUqggnHcwYfsmW4voGhKJiUdxuK9kVy0HJKX0unRN1lOuguSsoZ2YhAoaN0ChxfT+yIHTY1GowTW06V1NKTTkD0F7l6mqIsRBi+eL6vNaGPcmy19C9+9xFuAWkq6LpNtY1DUE=","layer_level":4},{"id":"124ac55f-1c6c-431f-8ee1-bcb309cc1a47","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"唯一性/重复值检查","description":"uniqueness-checks","prompt":"开发唯一性/重复值检查规则的详细文档。深入分析ColumnUnique和ColumnDuplicate规则的实现机制,解释其如何检测数据重复问题。详细描述算法复杂度、索引利用情况和大数据量下的性能表现。提供配置参数说明、使用场景示例和与其他质量规则的协同应用方案。包含针对不同数据类型的优化策略和常见陷阱规避方法。","parent_id":"8195f94f-7c42-40f0-8e98-ab1163cac8ae","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnUnique.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnDuplicate.java","gmt_create":"2025-12-25T23:47:36+08:00","gmt_modified":"2025-12-26T08:11:36+08:00","raw_data":"WikiEncrypted:AL8ErlhK5P9v0sHVTod29vf2K729/gY6j7UFgP528MxDbzTd1XQlJ38nvIgwYVs3x4UbNyoDaBrnElUAsDiTuTnTKFWZt6rAFSlbU38ZkmfPDQyKRaaYX4Y/yV7JOQUveGTqBNuIKs8fiYeBfb6i4woHARb1alu5YRVXXL67bBkHFEVQsakKwRACmSjoSwZcgMQdqgUnZZbk/s1iL8Pr0/hfnRt7TnVj4NwNDaIPz8rJyFLkUNg9je7GPiXRVIkFDzV6eg23GvArIyLbP+pmJTVtC5mtcjtAQY6Vfgm+PYZcSOrirDTvkrnJBewHHxGxSW74dnv0kSj3csrJyW1I0fbl/B+tP1hjrcNZR61sBnUytSGdQroB5yxtCccw5+Z79FzspEMFOgr9BPm1raI96EFWAaT5Xloin4L7VXIAtj+kHMsLFyEmK4Dt1ERe9w98WykLbAuxNiSHtUt3F8rq0JgXQ7saMMLSl10vwbbKNqspaBlHQhjBb5DMyHviv4vWxZP/Bu9joEFkHZfJ6BUYefG8vYV+6FZzBJrUsFqkHfzTNWNBkW6k0TYE++XcGx+S4rnnATSQEzt42kLVWAt5GPTcGn5FCnG0CHnrYL80iYYsSALeYAmLHvRGDKKne0dQB/ChYoB4x+Klc8OIgsk5zO16+eO1nKIot3YGu3t+wPR9fAr5rrcyJ6hJBoL43ZuC0Lpvxd3oC2yjSWOANVw6vEEuGzr25ktFiJN1eFiCe8HFth4GlHhQp49b6Yv6OixywoBHKGGJd4ptSJ01Ses77tq2Vzu68FbflwxJWlYJNs1iP4eAmKGHQj4LodR8EpJgUo3sNWq3GG2dC168yJaOvXywpguwIQqBjPKuyOhAwtCXvf9Mex4l1oCn/7csQK0WHlfPwCORbEO9z+yzW7czIVkOXixdeQW3NZ7EDVQbhURovujQhqu74oQwrtv/0CmWLMhZoW6cZOILl31doBD6+qoMxjLeRZYMaNWqJwEVSNJeuroR8jvQ5FueYeC7Vwu1WsCNsS6jdcK1nwy8Cvq0okGJwWCFBfuvdtX+PkkvdyX0fi9XQQ34ITtudM7oZlQFEVtoJfC2tIP7EGoCLPtfLjkBJcQhhkFB8WXhE7fz8pHU2/PccvQFyWgifvg7dIY9","layer_level":4},{"id":"d949eab0-e738-4746-91b5-0356c783ba8e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"周平均值策略","description":"weekly-avg-strategy","prompt":"创建周平均值预期值策略的详细文档。深入分析WeeklyAvg和SparkWeeklyAvg类的实现机制,解释其如何计算一周内数据的平均值。详细说明该策略的周时间窗口处理逻辑、数据采样周期和Spark分布式计算优化。提供配置参数说明和在业务监控中的应用案例,如周活跃用户数趋势分析。讨论跨周数据边界处理和时区影响。","parent_id":"489baeb5-14c4-4d03-b73b-be142d956487","order":1,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/WeeklyAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/SparkWeeklyAvg.java","gmt_create":"2025-12-25T23:47:37+08:00","gmt_modified":"2025-12-26T08:32:28+08:00","raw_data":"WikiEncrypted:vw1CVZgFMfHnD66I7JkV46/I/zem2cWQzkQEUclXphIz53n9ezkTNVVw1R6+xuU7ajZsm7iltP8FK5Fl2nNea+YKK/fSq41uO56DdJjd60rN1c+DTd48WLPXucxaT+ch/Ugici7Gb19qwomC+JSDb3nJab28mU2/dhtAu8qj9Zgm8OU966ctwVQNGjyXPoChcfPpcqMGHMWRGPqqKFwY1vM/dCICAcklfbaAEBq6vyk5Em5lZJVRFC/Y3ih3g48hge0Z69jdiXOCoG/TdslNlncYJmI41K7nlsqlvmoMDhajm9DrPcveXGeHkoSpe9zLmfrn4qkdYvSXypujOqy5rNoLIAwvH/5t8GI7P/cLQLYman+15x2M7Hk+AuRrEZuA88YWOZtWKejDRGGJlpZ2/CAo6oTtTcDuayr23u/P/HhN0Zwvk6YHPTxJXcMqMoEWTvlUN8jVFfVEKsn44PFKKdoWHmRZeT6vZG5n44kgL4Tc/uN5NIXpiVr74r2s/vtE5o7UUx8046MNs9AQtMnf7J4fUaNhTa0PkQ5Z6bc0U38RWBOBQtbpRqVuYGF7akRO34JF9OjABwEt7+ZLew8ZPO23FliE0T9DHWEWYgpkY8ya6YeJ8VVbK1u07gXL4BrpPxPZ+3CWxNtBLaSL1o64N+xIdi53InN28Z1OqO5i59jwZI2GJoCGcR+JrhmyxJbQb+JZ8x8DcnBhUl6zSzOScmz8599ijtk2ylUqvHhETgDH6JVEFZZ5rEiv8K+qsPCrdUQg53OnX83vcXxaJbdylDfJOuSeadp9iOc49exZwCC3486TjAWuCBBCm/NtwG9a5/BelY+sgJeCRJ0Yn3304z4yn8RysRDNdXMYD/kfdZIdm5aklnw4ez/gd3QTJRDdW0I3VolIEygb9J1eNqcGeWkDDBe5WJKgnpcBQnqjVEnO/hhMYxduK2inKb6TZmoe/F2/R6vhUoMYxTOuM29YQJ2eu8JX4gPNJ8+hLmoiugVL7oZHrBcVldP6gz2kMbBhNOYoNgWuHQsN4ACJ++Ny2HSKD7i2JKvi8py1qBBSfI2z1EYb6nMUQd8EmUrvM+JjHn7AWW9YYiD6QMgLH4g9FnMS0piz0xYqDUZFgD5pWJAA+OHtu/+8MbwP5uLWgerLAsdxApAZVqB7PkZ7YYj9uQ==","layer_level":4},{"id":"401be447-6b3e-436c-8d7e-a0845a921e20","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"架构设计","description":"architecture-design","prompt":"创建DataVines的架构设计文档,详细描述其微内核架构和组件交互模式。解释核心服务(Server)、执行引擎(Engine)、连接器(Connector)和插件系统(SPI)之间的关系和数据流。绘制系统上下文图和组件图,说明各模块的职责边界。深入分析SPI机制如何实现插件化扩展,包括类加载、服务发现和实例化过程。描述任务调度流程,从用户请求到结果返回的完整生命周期。讨论架构设计中的技术决策、权衡和约束。提供可扩展性、可靠性和性能方面的设计考虑。","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/DataVinesServer.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java,datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-25T23:49:34+08:00","raw_data":"WikiEncrypted:EPw1VhZSv2AMLpYzHbCG5QXmatSKh1iukhkKRz99kcVPFHJKZVqOFStJHt5slSqzsunLJoqpKyeDoj/jTKKfGVSbyIROH7jwgYSNohZHWNSWym2PH9g+uBMtlBf7+iczPYa+ole8WL/Mi2uPZmxkJfZHzGBzwQlETNte7z1+QDE0LbWyW2YWV1tC6GbwQY1wvoO1XVbrRgd7oQvAf2Tw5HNt+TssZcde14YqaIV5/3+cRq1xlgyIOs2TT5SiBU3ifn0amsWFe2mkCOBSn9FyqkxRdS9yltaJSud6IAZ/w2IsaE4fTUJEAzmns18lekmlR0yznSbht+Rb9I5unLOyahkIvtTUZWmrCAZ766r+RTVVDx2ZP9EdTycPLv28gcAuNuE0RyPvsqBDCa7zAccbS8Tj2DgcYPfYtKUmHX/+YXoAG+ydqcoXI2XnJszJnxwubQEWdRMbrPbEj+VHPS5HPIwLlSSAbRF/zmLf2A0X/qQgcQvvtwNsgj1PNeIo36JpeIg3vf6SqkYqtjTf5YAv5j50kUmrWPljikNi2/rt3mO4+WscNHXq9Bx26IHNzITUL3hWj1nMDta7oJOUMeEpp+0lDoT0fdYPsoRTZ+Z1A1e3SPzIJ4Cwt4UBa9Hyn/+U78iQkr9+9Q0HtYdxFxliaV1Ft9/hjltrhzolCZ90zRnTat/CcTTHu/lXTh5hukB3a8yxJCDSESEyAQmb0/uW+MWKAKeBHWzPrHQVnCxAy0OPNveVtf1g+rJc9Txa+q+ffdcB9xvOBX3YMyXI8B1iQpy7ccQEUXR2ez/577J0Y+MsOQGnrKsCKaaDOAmuD1FcXsMDsaRCRm5DF32+vyiMH4M78AnzhqiH+nXGBBzHR+i4J+vuMxiWjPXpCOiFH4iSj+b+gCDbXBHI0XOCck0ZD2Qa8Hk62JfkcfF1rQdnRmT8i8GPTwk8I6FXREKRty6KuKhkjYSmYhhzYF6hygz4buBxU1gD8GLdZdHWh4bKKRKdINZqIgpqo1XNuRka3SwVb21bRgt8de0UaDKmzq6KdgihZl2FdePBwlD6mAfbPCxQTP3YdE0w0u5lOdJNpFGfEjwPdiMQJkTkiX4RbSVJz3a0/JHI2ZQewPRYU7emtQzQ9e9dMeWbRvvQhE4C785pYOEjw3tWWJB/UszgvheMNUabzxrCTRYDgLZnkzYLHSTgfUCLHtE/CkQwTMlH+pabi5c11h03HkgHzY6aFSUnZk/e4HLTnW8AV8Kw3cJPpDFC/GEmwo0C+IJouP+T9/OW73bCg2spHh5OX4IHlf55Vzje5D1ZmcEqTNk7Aaa+XuqUXoXUKgz/QMEZDpv4aJ+qTRAY0NXQETMTEe4VQmALAsKHMpdt62HIYaapum2COnsWdDywEn3LO1YTen3foRjL4C5O1T7+IXJS69XDoxP9kbd91xxW5Sn2YnYV0BWoU/r3RRe2jrZY6SW74JyucjBGhXTLUr3pjYhpGyEXmflaEewgMMCJcQpd52XRYGcl2KTq4gSuAlIe+QnrJaxRvUI1aDcDc/JeMXxDaHcFITyuVEawgG7bjSmEFC808drxNKHTYI6jxuwihVxzOx946AG9"},{"id":"43eef860-d2bc-4625-a145-101fca77c030","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据画像","description":"data-profiling","prompt":"开发数据画像功能文档,详细解释DataVines的数据画像能力。描述数据画像的采集内容,包括行数统计、列类型识别、数据分布、空值率、唯一值率等特征指标。说明画像数据的存储结构和更新机制。解释如何通过配置文件或API触发数据画像任务。描述画像结果在数据目录中的展示方式,包括趋势图、分布图等可视化形式。提供数据画像的使用场景,如数据探索、数据质量基线建立、数据异常检测等。涵盖不同执行引擎(Spark、Flink、Local)对画像任务的支持情况。提供实际使用示例,包括如何为特定表配置画像任务、查询历史画像数据等。解决常见问题,如画像任务性能、大规模数据处理等。","parent_id":"68f6e22d-b8a3-4a52-90f3-e23d8a3f0f4a","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java,datavines-engine/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalDataProfileMetricBuilder.java,datavines-engine/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/SparkDataProfileMetricBuilder.java,datavines-engine/datavines-engine-flink-config/src/main/java/io/datavines/engine/flink/config/FlinkDataProfileMetricBuilder.java,datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityProfile.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityProfileServiceImpl.java","gmt_create":"2025-12-25T23:41:06+08:00","gmt_modified":"2025-12-26T00:19:06+08:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"a8f7f5d5-bf23-426d-9273-02f47623381e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"插件机制","description":"plugin-mechanism","prompt":"创建DataVines插件机制文档,深入分析基于SPI的插件化架构。解释PluginLoader如何实现服务发现和类加载,包括类路径扫描、元数据解析和实例化过程。描述META-INF/plugins目录的约定和实现机制。分析插件生命周期管理,从加载、初始化到销毁的完整流程。说明插件配置和参数传递机制。提供自定义插件开发指南,包括接口实现、服务注册和测试验证。讨论插件安全性和版本兼容性问题。","parent_id":"401be447-6b3e-436c-8d7e-a0845a921e20","order":2,"progress_status":"completed","dependent_files":"datavines-spi/src/main/java/io/datavines/spi/PluginLoader.java,datavines-spi/src/main/java/io/datavines/spi/SPI.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java","gmt_create":"2025-12-25T23:41:09+08:00","gmt_modified":"2025-12-26T00:19:40+08:00","raw_data":"WikiEncrypted:ukPV2tcWPRGn89Upsee0BJLR4V1cg+V7Kyc9NDUuxxR9OCKWJpZQanzlf1yeImLUFcjsWx/vxZXuhVS7c+DoRrsWPyZgpK/LNm4ctB6LQyO3tzxfjNj7givgOh4uIpF6J6uYaDW5f9uVreH0WipCLf83pOjm+dJaPfRuszL2ZIckFVB1YiYAc7xpJP7xIVT/M71OzqubtF+8/c4Gna1/ORSlTLSMMBz3Ac6ENH4I3BOkp7bNMu6yWsp3xAV1nQF5ZfTia/AF0KNVvHi9pwkJZz//0/mkktgRcZkzqaQqPy+55B8WXR81xFjcR1dUAwPv3FzR3z289a0a1J5N63Ic+lovacxRjxPAAnEX4fqcDDXdhyL8qkBQvtnx7PaVN41+i56peHj88lVNeGeVtOkROfp2ImBoEdRZdI2dNvwooNiR4Urgm/yua4MEgl2k2dIG4aWg37BJZ1v7c81nJnC8KnslVlCm1ouKgpaM/nE6pPuy+DJyIqsZI0uVYbxd9P8y2GReAStWYY0xHBiQ9RSewAkUq595g62agAumj6K2+OPW2W6KGxrqddSQVZHBSvn7ZSEG3j9JPewDEcEJrkPJ2oVA2UB1z795/6fkjJzqhHmuIMn90kKdY4/ks11j1U38dkSCkhgMngnMIBsEEG/pyhvldgu5BZkv8f3D1BgT7LtS96FGrCxSTjlPaYJ+B0Yc5r44JaYORFoQk/3nV/HHgzmY3wOHROX4QlKT/C8L2ceuH2Kc3Z4FuaGPriMB0K5u/zLkdgJdrM/7CqO4wBo+1che1OoKpTEab4LA0sNZP607t4hDJvupVJw6KPKYmXurPgF9r0sdu9KwfwZ+J2LdoSFSO1JDHArRXJRMnvtUvee2WZhkyvMvZ1ufXzR86Y0RcsvRecxeEizYKJb0GGxvV+n4yhYL+cL2tFd56TvuIAd386JIO24GDwfYVmOHZVw+Y/SkUG+4UbAMPVbXduM8GhjNOkf68jQqocv2RldZebnhbpnOONGNqvDsYSMqgCYQlQhoUkfVcS8Mp4TmSpK7w6qODwV5bhP50zr4AKpYD3unuGJX3CjEgyC9lOOFhFG4LfjYeqj/ER8XIL8rAsGGQVX7uD7aHH81Tw5ifCHhwxoVgQOgqu1sSuIiBy1xH/20xl3uCo67TR6Qy0/E56451C4Itwcm9KjAvq0YulIviixQ+r0YwudxBnSuwUirPRPnwePey7FV0KLy+e1yXnERWWlO3GKo55PYn7j2RFf6NHM114V6HGU24o4nGo0Z9oEMPXw8VOpvFcSKRMczxpv0IZTEsEOxZ9YKpfqXkhKTcgzisgg5OSl6rijKwi8D8ivcVb1RsOxfpt/+jr68rPf+KLLjranFwo3ujjrId5jBkQOl/HqgxOfDWg3T2ClhfsMuusaxWS4I1osX/AQwo69w6A==","layer_level":1},{"id":"e4bd9d6a-26b3-44a7-957d-46e0c9ba5cd7","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"datavines-connector模块","description":"connector-module","prompt":"创建datavines-connector模块的详细文档。解释该模块作为数据源连接器的作用,包括JDBC连接管理、SQL执行、元数据获取和方言处理等功能。详细描述支持的各种数据库类型(MySQL、PostgreSQL、Oracle等)及其特定实现。分析连接池管理、连接测试和故障恢复机制。提供自定义连接器的开发指南和SPI接口使用说明。包含连接参数配置的最佳实践和性能优化建议。","parent_id":"c391a73d-20a9-4e3e-b13d-54fba38ef59d","order":2,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java,datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/DataSourceClient.java,datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java,datavines-common/src/main/java/io/datavines/common/datasource/jdbc/JdbcDataSourceManager.java","gmt_create":"2025-12-25T23:41:22+08:00","gmt_modified":"2026-01-29T21:49:21.9742627+08:00","raw_data":"WikiEncrypted:SIXWcxxyg1MlRY3exFru4lFtexA/I+A1+qPVIRuJacV6u00KABNBQ5xmmUKMqJjmL3H131PETtjMpAJwC8Y6Ykbs+MFw3Pcc0kJ7xWsuv7QQR7D3m2h4UUpwcKdgr+zI5A9aXTUwbiHCKQCh7s3GiHle/l8jTKkm66TDVZQ/T246BepTuCBM35oK1uGcJ3v1tT6fuBQPzb+fjA015a1mCtZTvfh2XOUnBaqwG7yX+WCgOzyr5e5LuaypQsueAUeaNf6tIjN78GpXQ7SV7R+kja8nwsnSHMoPbuLnZgnIiJEoJyo+CEvm7AaSDHOkbsrCq1gg4xq468mpUE2+GzMwpXr9WSrsgwIqdE1LTmrxCrItCXHbhENwwpvmHdzG3PLB5PqJ68jTOUyVyBlC2poAkaaZAUuu4JiZD9s6XlK721zq06iJmfDuZwiw7H1T/VoOEneD4MllaD/TpBuScACIxXi98HKFxigoKgARBZNkpl/nwak1j+IotUQmaB56ZxdN4xWGtaUx8O+9YR6lZJT7FhN1acdj/v6CkGJQn5rChwuIje/oaIsbv63G+gEIhoJVcc/nmtTgbmTGrd+gMZWYT5qDppGI3yDCibCd0Hpx3kziELuuB/WJQrVAoMhMvoxxb9JfIwXyeaLzRv0mR9LjAZgBVpmoLX80zQYpuBixNE0LQVQr39js2QO9xZz1Y+PhoQAQFwHPd0OPIVE48qbyxxcOcAVgbXTm4f2A8AlZ0avx8b5QX0KvrioxK/MW50qrvh1gFn58ytAiR7+JChQcRxiChPu/TKPsCqRCWWkZ3UYnKZcTj0/nvNT114SrJ2HULJL5aZ+Ux6JfXKa5e6Hw1ZDyeD7b9lcMlhba/j7S8MBDDfsFhuvIijhiyWjaU8qplu7Dw2BML0KIdiOVJhDjf6mOvEPLNxeoUsUuutlNtkXlzuE8MrDWMfQxwl015u/n78EUZFb4XKZ4C6QHetKkq4ZhmHGpNcgwoAoeFP9LEnBdvMDa7/eGw/+bMwjmVsx+5U9UwyS4a5DFdNXJ1U9BXl3prLl3G9M+LyktYlDUnD52gSZRubogJQr51mFQHJLeSjAhjh2toDOl7T3ewdzAfBcdxwAgPuWDIOgzWtYw2x0y2nCoatgvkRgtZcZqJbIWI6xqWSskJ7oTGw9VtsEzqSdTF8mINMPU69Hwi3gPcuXvpZWTJ/bVSuangtSxWFh3vbVkZzU97yKXSu3i6GGc3VUlKFKtFhwMtMhI8jfQx7LuBoYbBqAkObyv0bSjfQzyKRceBQiv2+jDKDRM6Hm0StMadaS3fy3ZfQdgbHESR8aw1aEteHpjXKs/u8LWkLze5l8rlJ7UOguh4zcTmdZFAPQFulhSCElSqO9ZjIn+f+Ho6oZWjQdSLRVZ190AuPODclFv/mSqj5x6FbfCJEiO1d6A8NwWE++/K/WGjjeYr7lIapdcPi08rnm4nj9x7eJBbOhpxgrCEAZC99ofeGpzqd9GW5o6BVNlQHgIIczQ1Z+OWK5K/wqVSHMP9f9JHTXSTq2KBzhS2ordUnSlPGEbx2dHiA5w9vUpHhD0VKXAq1O45dYEiR7yp9p3u3Elqb+yy+8NXw1ttHLmiacj8+LKlOk23Zy5Z3D/CNwnlI9899RoLCyIA5Q85H06wwngmDZ6dGfoxXDOxW7lovgK83gLFrgIQZXkeHDGRPdiJx/50a6qtSIZa1yO8C3I/sBjrkfZ6DC/THMmdmRaZ+u7QdMvemQgBgIEsHE1YkT2uuoslim4kwsMX+CmXYoy6ZH5/nSWuqwoHdNwKofD7SQ4k6ZE25r99QJpvLSMGGv7M+GbpI4OhNja93XeU59x3nX8unQ3LjDQOgfPaBrQWn+z1hD9WgrLxXCqYPtdxuv40dzyTOI=","layer_level":1},{"id":"5d98f3f9-508e-492f-a764-85a92d4c5c3b","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行引擎插件开发","description":"engine-plugin","prompt":"开发执行引擎插件开发指南,详细介绍如何为DataVines开发新的执行引擎插件。解释EngineExecutor接口的核心方法和RuntimeEnvironment的配置方式。提供Spark、Flink和本地执行引擎的实现示例,展示如何处理任务提交、状态监控和结果获取。涵盖不同执行平台(Yarn、Livy、本地)的适配方法。指导开发者如何实现执行参数的解析和命令行构造。包含执行日志收集、错误处理和资源清理的最佳实践。","parent_id":"f7482163-91b0-43ed-b702-cebf50029b91","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java,datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/env/RuntimeEnvironment.java,datavines-engine/datavines-engine-plugins/datavines-engine-spark/datavines-engine-spark-executor/src/main/java/io/datavines/engine/spark/executor/SparkEngineExecutor.java,datavines-engine/datavines-engine-plugins/datavines-engine-flink/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java,datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java","gmt_create":"2025-12-25T23:41:31+08:00","gmt_modified":"2025-12-26T00:21:04+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJzQJYqilKnt6P4Yv5Mjml+/DvLko2YmIn7+0l1wK7/vyPbYDqXKH37rU+f0npf0Q/Mj6hV/aEAWgMy47W+LLfQ5xrGOMTE3Kbf3JJmo8wFex9hxXTQBeKZ2OFr5zx2lXVnuubEUhkyyKMKwEF04BQOb044Eqg7w+6gsHV5wrsA9oKjxC0065Z8RAJfwXuLOxhl1oFRobYatyi8xV43FY3IosG+3XjMStKxXQ8vw0jAcMPuB8zQEvC0IoyQ+ZeXDC2HUSzrIdxINiSmAcP7aXNnjuv16zIxMWyDQ1utm7niy6s6SMjyFXoWFO1R9/pWf1vAovW9ySMUGEzTWw7csTy5irb0dfoZeUu1Dz6/PPxWQ3D+zO0OM1xE+X+eKG/91L0SFhK0Onze1ujuL2RK1LLe+u9Lc5QfuOElikcHFQFDhiM//TzMBusc+vWy86cULysvDx0YMqD0V2GeohDkuquY6TGhNhw11R3DIJHEYXPubrmfnBoi48vF6UMb3kgO4tCUO08ItB6jLWsJxq4BYs47aZMPQOhH80SRikRjVopjQtYRi/kvNxsPjnmfG1L5lHaf4ziT9ZmPc7kIxxgpOQOb7LbAajUkeGdHahXEXZqRY8Mp/ntsf59VIIBvunRsNGxyZo1baCs9Mn7mVhc+px7or1kR8fV2eAkWEla2Hws35xnsofJnMLvc1r8krIasN6anRDQOsjshu1uM3fCNab4FCeOv8mF4iZQTHPSa8uOUBvTEGZr38J6sfE7Yrcs5l65sgNFF03ZvWcgSswLJkYI5+zE00sPBabY59lZpwLSwBHPbYW+W5pmEHuFfjul9V/st0xNw1F7p+lugVu6OnzIh7jtwVxrK9VLUPvXYA6k40Rr8jSJqZG580imsPryn/RCdunnyOqFBFZgiVv4ZmwHqZxKxFY1YPU5frp4+RXWVbQtmrYU7sZ5lKgPd6pIa0MYn1Edf3mUrjbi/pB7jangactPhNsyvREY/zL/krKbc6g5tFYSzyonp48vrtHJaWnMOOpem4Fr3Q+AoN2CSpz7RUeupODPV1nzdPpAGnkVv/gUJkvTip92+hyfThZqy96f4DPwnKyCcHxRxq53ORC69Y6i1PAOIUK3DO9oqcC3wlIwmJAhHAIscyR+y+1uibUh24hkq8uEKjz+iFToOAgewoadTbYcaMEBmKVcdYMqVeQmW6bfqHVNEHnGZpv4ZplRlcubcRjaPegT7ds41YeOzFr8Qo2dVOf+xJnT44f6ApWvvNZqvBf5HAktN9zagjsZlH6QYJRgemTOMKEmeF6U2PQxv/bcDIifU78roO6S4V6MdhlWMABjRtcgxX4XjHXUJRej6ugnBCynh8VVfqlDspvUPJF1nbSgQLCXAlWJHg0g2uBUDEMrShU+Q49al6Z3oyyEirJMUPR8L7J2P5aI1Fnxr+jKOeIMEvvA8mhWZ+aXmF6sv/XucG4U6JU62EiNSOMK9S/LqnAZjKrIPayBo6/wpYkUatXKR6yodu8hNW94A8oL67qJgmmpLiZssIOgZGlOJPUn9pkUO7uqgNlsOSC7bFgyLd6dse2lVy92kbiM8nYPDGV1FQtFw8/wvgLzBv8+fHQ8ZrOJpwQD2jNpOT+gzyyzPyxBl4UwkwibKBnGcJe0MmunzH2vhs+vHbwQY3r8P3a/wvrDQLC49s3UZ5mbu/BJm9m6tGCkbEUY4J28Xhc2U1QM1669OgKlhnH7uEcKyq9PRNcHB+Z8BrbzWmsyC5RqmOSbp1UFz2BnChRUnkHWvRP61FRBXSzhbOZzCZ8Js0P9xKPSfYSYgul12BV8W9a21EYSXv3nBeBvZGgfERznKVHVdZo8PdPcdvc077UOq8MS74/YHcBQZVQIC3ovL2r+z4+7gqSWcqYVJPVy9UsDhi/gUNEYQwRndpJQ7AHIfOa5tZIJ3kaZ4AaZ5umTPl4zpSi46LeXVKrrwte","layer_level":1},{"id":"c1bd61a1-afd7-4c7b-9136-b272c8038287","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务执行API","description":"job-execution-api","prompt":"创建任务执行API的详细文档,全面记录与任务执行实例相关的所有RESTful接口。详细描述查询任务执行历史、获取执行日志、查看执行结果和检查详细报告的API端点。文档化执行结果的JSON结构,包括总体执行状态、各检查项结果、错误数据详情等。提供分页查询、条件过滤等高级查询功能的使用方法。解释执行结果中各项指标的含义和计算方式。包含执行日志流式获取的API使用示例。为监控系统集成提供指导。","parent_id":"b4082be3-2f3e-42dd-89fa-9295da3c62a6","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionVO.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionCheckResultVO.java","gmt_create":"2025-12-25T23:41:32+08:00","gmt_modified":"2025-12-26T00:21:08+08:00","raw_data":"WikiEncrypted:yZ8o4WQI5gFnMpMgO6202ahRz4ZYHU4kzuOmxISNJDXcC0V1AbCgk4tbNZ0r209P7KWZGbRiU+20Rx7sAtKfgSqOIzRoUw5hgW45rq8z3WSpY+z23S+5gP8OclP1ZIOfaK5CByw+3FEe2ROGQK+tgN1OttPybC0gNPDZHQklqS+KnegqN6E1u28uU9qLc9VcOHu72jojkxYwPhKUNqj5yMVohzEUc4il6AkKoVSoWZyRA/CnAfAoBT+zvtIE6SjanyLOTK0+IUfaO7Dtb6cPVn79kB9OdMQns4g27V7CkpCEcPFTR6ogzmTx4oIS6upaLSkkXlbREK6lg5Bxx/SwYGPKCn+euVE1Ds9EU7GQ7zNEPeXrTnPtQ1haiy32TkjAfFpnRzihottbHW6mKL1jC61qzyINiRYH4KMj9vByBGLaVTUnR+aEol8bYvL3iDBq2nZld+ns35hfxC5bvjg2M5YwwkjPVve4p4ZpRV39UIA96jNlsFdYWFJJwlhY5G87TPNRuka/DcVqkWcvdVvTa66k+duDuQoNDuzzkf9Munp6bNuDO6Rm2WAXwM0h/HnNEU7ijGsH1WNmmerHZVvQwe11bOji8acVuNnSKOJNbFbgBtpCPNEDK9O8DqykUj8nDBmETdnxkrgTIacjH5gptEMbCEE3JR+WLeQBdxhQzVysVPSUSoPkeuXWQhIaQ9CDJYqo17D0U4cVk9mw096wiQ6aIJ+hPh2X924rs5NMfhLT09vMbBhmtopTYsktkH7G5RN7lBnlnLxNf70bbFWldPZya3zhNhb98ZcLtMiadNgh1ejmTsksEL6kvZ1q38XXTHAwNBNCPyqwqsLzfqRgH+DPmiT2CuFLNkFxPjh08JmNrQSr+u4opwyQ5/gm5d0nthbqT+2XN+01E32gltRMJqYS2Fio28AWtPYieP7Q2fjsXBQe5Fts8DaL0HKa07e7pldFP4q1Gq1wq57Dqq94D5njWim9riKg07yGifUQVoUCQEkQa46qhskRQOdLlS8HpjIHtjX2Toj+Q1DsjfxKj7NUdWwY9siLA6L5XExhBzFXyNX0OxmIvpEEqQIW/IkAPQUWbFa+BuaP6WhPb9JrX+zQMjGLrQGWNU2zyhuTzqaKYkZX/EKQC7P31hqUIxQtqDTGSICeFxcT6q/P+zL5CamI10qQ+Cup2R0WRQUu8MeNsi5BmUhhiZ9214jyFr82yKWi/Noc1lGk8FX9tQW5+f6z/iv7npDyfOhp4iM3Be4VHvmIfHr/sqTez19iLZOI6e3oLmyJbLzOsGPKFA9o3MV4ELgAFiPvd3hb79JR8TUJy70WgDY6yXdH7OMQidyruyCOQZuYL6vTOuGrckVy2ekL3FITGnHACHTv+nWRlJwoP3tXg4NRiBcDANvIu/pv/lxp64R9bsjkN9lYgLwv3NVWw6LVYQusAOgKXD76RN4C28yMgvCdWn0AoScc8B9KlomNGadZaw8SKEzUwWZ+/ZbTV+douh8ExFfwEER54PmW+HvxgO9vT18R6lER6prr58xPoKjoX4w4o1dIEzQgdQtHO7erfr4Cq9F5PxvP4k8GjUzRXI6YnCJg7i7Ri5cl","layer_level":1},{"id":"b50778ec-d4d7-413e-9090-8187cd6aaaef","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Docker Compose部署","description":"docker-compose-deployment","prompt":"开发Docker Compose部署指南,详细介绍如何使用docker-compose.yaml文件一键部署完整的DataVines环境。详细解析docker-compose.yaml文件中的服务定义,包括datavines-server、数据库等服务的配置。说明.env文件的使用方法和环境变量配置。提供网络配置、数据卷管理、服务依赖关系设置的详细指导。包含多容器环境下的日志聚合、服务间通信和健康检查配置。提供生产环境部署的建议,如资源限制、重启策略和监控集成。","parent_id":"a5e4da90-df85-444b-85e1-80088657b90e","order":2,"progress_status":"completed","dependent_files":"deploy/compose/docker-compose.yaml,deploy/compose/.env,deploy/docker/Dockerfile","gmt_create":"2025-12-25T23:41:37+08:00","gmt_modified":"2025-12-26T00:22:13+08:00","raw_data":"WikiEncrypted:h7ADvj4WLJHyulzCl+z7kLqa8j2Vv2XLgyupfYtBiaAXf85YeSDqXjeKeQZwRW+8TpLexklAywQKvmdA0mnK/HLiEj2+0CoO8O5k6fT16Cz+5mA8HmH5HsVViyZrBJHAHPmlTI/7ghvZC0aO7ecBs9uq1vnvhJap0ks5VqEZl6fqyFIrbLMQ19BsP9q8XzT/efBrJRTJ9JQ9mFCSc91XXnqTkf7+HElcx8uBEtqWEwXz6FoQbMRU1KzqUHDn2CaXNtyWq2ORBSIrS4hL5VF6Z5RbyDxloiNRWrsh2HKWcaXtgnwAW8hblJOc4UCPckrPRO0JZ25k2XCRt14S7asSScXGVW7aE+Y6vDDfZhPPRZGK6YngO3RK0alRWs5nmOXwriWYEZ4L/kJN5aX+y8u8dJ+lRItDjGIFMwp8k97GvVe4uB735sK6abyFJVcBoySYevLYo+fVhDFGcW0ZfhA9aFzS/329OfeJejrZOz9VjuLz3gt64w+0xms+r5mKQkhQUf0ae6NSU7p1JS3BiUWfwzFJdFqGl70gnQM/g5511AWN1JFEBeR6vfOeUSwlZ10EXUm90Kc2Y7M6q/iB8p88JdGsyVzgcGaQ4wA3Slm4BRI+mwbV4Gzl1sVws1USt2C9fFVszAnQKW5DBXmWT0R7FJY9bw6xTonP06KyqF9y8sZGprGYB7e0A/BAKOao1J5NP41nOq12xL5T7cxQ76eJOdm0qc8QFaobvdK/1l470tN2UDt3LRIJM1M/3S1k+mfzq5oXMKSSlOKODUw171r99HGDIyFWAN0ihMyxZ6aQIm5oJz2XRmo/XYYOXEWqodlcSRyc6vs35QtvDiJMPd9Hl2I2oeBiruNG6Jc6M9WtK5ORf17//YFWolmAIjfrfnzIKXpQUAjBMerRx/rdd0+cjIxsXutDuhmUxb+lODtZ5WWOKxhjSZlVCAYr/pvfMTkydvtE6cm9tVKmuxPvnjq79EEUAaqCwoBh8CLOq7UmYpnTdo777Unhs7Yx3II3mt3fTTjsEihqoCnY15jVRByjH1I6jk6/kA5n7A78lkGmkVF23h916BUH8xD0MWqLNCVtreOJvmIk7c57LiY+Tj4m8v186MEs7K4tUj5Spu4w9KVp5gSw1Rk0OvhfVOx1GniWQvFv3rCZ4qQYKg1Oit9wWA==","layer_level":1},{"id":"14cc37db-076b-4a7f-b521-37bfc7392126","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"索引策略","description":"index-strategy","prompt":"创建DataVines数据库索引策略文档。分析当前数据库中的所有索引,包括主键、唯一索引和普通索引。解释每个关键索引的设计目的和优化目标,如加速任务执行查询、提高数据源检索性能等。提供索引的创建语句和在SQL脚本中的位置。分析查询执行计划,展示索引如何影响查询性能。为常见的查询模式推荐最佳索引策略。文档化索引维护的最佳实践,包括何时创建新索引、何时删除无用索引。","parent_id":"1a586877-260a-4728-a2fa-ba930f91fad6","order":2,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/resources/mapper/DataSourceMapper.xml,datavines-server/src/main/resources/mapper/JobExecutionMapper.xml,datavines-server/src/main/resources/mapper/JobMapper.xml","gmt_create":"2025-12-25T23:41:51+08:00","gmt_modified":"2025-12-26T00:23:25+08:00","raw_data":"WikiEncrypted:CW4U4O1XL1zROhAm0cNswByX6mGjTgXaepqMZzzD2dxTXTqyrnODSXxztPcMW4a7WbG87iij1+87p2jkzsTbhvNAmkH5lZJMYeK9bv4/l866uKJ9k3jL/KnS0nFvYHrV1JJPa7CDiyulj3MVsyiSJk1eFINFYJNcyL/Io7OtSZh1EL/m/bhwwcb5199CqzUp51ObcJG1kL0ipbwu9/Iu3cTrou0sfhuNw1RrdKZLH9Du1pSClt/zcMreVpF5BbSp3B7HbFiMg9doBU5NOhAXZKXRnH1sB021FXI28NxQ455kor9NWCGfDSFIqrA2Hzepo3lsJ+xsgaepSAeGlk8hjImJNtQEQ6/4t9o8Ab9hd5aY/7S71OjzrTbrWDGTpL8IjTg3l192WEmOxVmFKufoGQeRHOfMp1SGZ2OhJxl6ghMJ1rRO6hN5IqeJd+wpm0YjT8sCJGX9sWMueo1CgiePi35Ncymw4scFWJN4LY66utitwXrgqG6nOA/xj71GO9cADp1mpgmGrP0ty4a9BZe9RmDwedYU87uOKVni9n1AeH9qb8/r68IDIVNPeBjZQuS6C9drB9QAr2KN4Ir27EcJ0o9SIiSXvvT1ZAYJQBIo52CVKUjsU4QBlT5kJvk48q7lQXJI0Sd4QWsUM607yeitRFgpIkFQyC91rc12Orcn9Yi+rzJn7c5Vs5g5lw0ZbEYdxoMiXWPbhWnC+ZglwiDfxqJud2hjdhIo6CYKUGmc6D1UKYz8jsIEdhjzi4WsigOPcHzH/OHQH/A5VGzKC+de/5JH/HMwvv1vBH7CorG6M5wxcqjn+FQynFuU/SrOoj6KS6mjkJQY+yUrRy/4vbWuemsBLWPS6yJzgqG5I6KlStHbbhBLb/vZwdD+f5yR7NT62fFVDKo0H0nhiSJ9v76Sgwu09Db1psKBKRZbaIjyW+eGXKc93n+Hf2rLUMwl+dIvNQj72zyqLINg0pDIq3MFePIPeK0YLI0iMoxS+wKiflRTr3wjCOGCNsJo2PE7BpFT+eID/jKYb1txCa+yJv3saNpR83LY//LU9wk2iwBrHaPo//TM/XQD9pEJuOALP89F15US5FOAafb3x4ZQi8pf/mK9log3ItWhy5Rzd9kBqV2kBur+E/MaxlSvLvBaet9IbXeu6bANb6rWjldpZVVzC1j02UTWvki9iDQRkp/SUd7rYOh+phGYjjwr4VkY2yJmNyFC/BU8blKRfazfAOmYrgBPV/q9zqFT0PoCAH97LUpxlaLgS0L7drfqLtR0J02r0Ttn9lrmwJNdRa0obgnHaA==","layer_level":1},{"id":"586fb977-73cd-4d21-81a4-ecfb619947f0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"变更监控","description":"change-monitoring","prompt":"开发变更监控功能文档,详细解释DataVines中数据目录变更监控的实现机制。描述CatalogSchemaChange实体的结构和用途,说明如何记录数据表结构的变更历史。阐述元数据自动采集的调度机制,包括定时任务的配置和执行流程。详细说明变更检测算法的工作原理,如何识别新增、修改、删除等不同类型的变更。提供变更通知的配置方法,支持邮件、钉钉等多种通知渠道。解释变更影响分析功能,展示如何评估变更对下游任务的影响。涵盖变更审批流程的配置和管理。解决常见问题,如变更检测延迟、误报等。","parent_id":"4bef343b-e06f-4b02-9a82-ced169b015ee","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java,datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutor.java,datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java","gmt_create":"2025-12-25T23:41:54+08:00","gmt_modified":"2025-12-26T01:02:13+08:00","raw_data":"WikiEncrypted:MTGOV8yMPpR4TI1lgrJ8xDfdxyWJRShO2yUW3QeDArDntNsXm7Tk+xaQ0aUwoJKB3JYx6I38nxEFR30ETHUsnRfVU9shlqK0uzfDVgCRS9c1Nu1Dk/4k/0J5XXBpE+ht7gGc8cbwAGiEZ9o9YTesDla95CXYLAReVrkkcM5ljWG2fA8J6WH6sJAPs+Tc2pqUGYYX5hTuWw5r3kFSQb1Y+an1C9EQ9WLGtQEsehIzFDwfeZm9B7ShSSAL1EXFAxJnit09FI59/2EnfeJxtpjRd0eu9+V+ruep4BA7M5wS/WNrPPv+OXkYboVPdWDAieGExMaf17HAyYGYvViwPGtN8AcIgm9ACwgLRnwm1JeuDrWPRVGt3EgtS3YRW7fjtwK/E8Cx0xsWnuS4g0PwmAWQw1L1Hhvy7RdLZEjqN9WTprQxyAkr79QKuG8FelUctZD5mSNPNSRCiye6DIShntPRbr/3AOpUPf3Vgr6SyKYBwKm0MbErHDl9S8klWzEanJWHl5oIwDug+nBN8tCTy8uXHlzi8OIjb8d0LQe7kewPCTg4XQYMS/uoSzSTVAwfSNumNR8sEqcga/UTvmd1tyvGC8GHP3d8/USqSyenpVwPtvcGXQrIzmw5nZzVWTrUTCcnA9HDLHF+OxGIOKGsJkBJ/Ltji22ZAVn9zbnkhcRNYvVPYRZz6lJqFRuc4gTKP2OiM4FEx7WtWCs69g7A8cFMAShDdQFVgGIVdq0qKloxtao9Ob7CplVVPlSB9k45FEIoJpxcUJa8fMfHrfr9dnjGUpknHeKL/i33CY0OrtXOGZQ8P6U69cnNcPhKY03XttdNRcZd7jgRpTu1ECw+CEuzUtA+dPYMEKHcMZlkCEy48VahSI3EYeZjpU4QYpfb7T4hoR5SEngTWFbJPE7WP7OYEDns3gc7STUr1U227MImaJgb1j0OOE/kBZzA1XZrv2cc4XtlX8TPZAzmrrjBRXtHs8rK6cgI7z3ENqWTaTitHuxhLPaK2EDljaJhzkgmJT/0mtZz01PvpWiquQQzybMHjMJaxySGqkMndBtFcx3DeamxgBZnxg76s+sM6WG+5Qg51vdSb6KRMbW8vjbNUbAE01aCEuOLivfefclCZ9LVW5H2sOagK1kiNYrWmEsLvw/zOHcGGocp/JGkOTd5E/nwOLp1dL4QUSLvQ/F5NvHXXRZhOKXXaITwOinayVs9aoMorXuQaEvHX6lX8Yoc7jgRMwKi4JIDklRPxRq/Q3keWxyPuT7CAeeSD/Zeyv7Kkc2LI1RWnhdLYwuKjUmPdbNT/efKo+xttLiT1w/WtaZCWSCS91eRhQDiuFpAjC5gK+IU4+3Xr+OGshEvVAytULqTmnkAyyPajd8XG0svZanGJpLwjXphZVvdgSL8pqIQeyUf9Gp5MF7ZkYgnmDOqakE0NcS8GPlfChACjgmfTtPRvb2DoatCUkezoyLAQsBU5ZZ+BEyuFfpxAR6hiE4No+R9NFyU6KNnrQpDgRAfz0mCki0Zi0w/+N4CzgYPdbHpxoY8gpHMtb2+RU7FOyBDIKKMH/Lun/emHJ1Dh0Uryqaa0KM59BI9KKK8d/OpnYCoNkGFqRzNoIEqMBY7YmzK0oHIn1vsu5MCe0SBWFoCKJmqnlA=","layer_level":2},{"id":"69630b5e-3d0e-49f6-884e-8e9fe153a0ff","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行引擎配置","description":"engine-configuration","prompt":"创建执行引擎配置文档,详细说明DataVines支持的各种执行引擎(如Local、Spark、Flink)的配置方法。包括引擎连接参数、资源分配、执行模式、超时设置等。解释如何配置Livy、Yarn等资源调度平台。提供不同执行引擎的性能对比和适用场景建议。说明如何配置执行环境的JVM参数、内存分配和GC策略,以及如何监控执行引擎的运行状态。","parent_id":"5d2798df-80b4-4ceb-b66b-9167054fa556","order":2,"progress_status":"completed","dependent_files":"datavines-engine-config/src/main/java/io/datavines/engine/config/DataVinesConfigurationManager.java,datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java,datavines-engine/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/BaseLocalConfigurationBuilder.java","gmt_create":"2025-12-25T23:42:01+08:00","gmt_modified":"2025-12-26T00:23:28+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJ/6GgkoteJRgUIqDxQrHJEuXTg686yp6Q3oGxDXAKbViH9lBkNnxQp9MeEw4J6a8MqdJXu6NQrucUwb/1wB+s/4aZo++euI2ROzSovntmjDn3wV6uC6Re2FYM+BOiywMS1mXlat8TFlXqlE1sbXD4JX3UgJXl85z0hSC5V3GzxPDm2RA7jp180OkzowpnxGAr1artg00+pQbYPxkE5PSiAKq2vnsHFhA0bqRBJT2L2HWDiS6CF272791tmx/eHiwy/qBoMlYyhQ2KVA0Pyvl7ujXgltrdx5EZVrZgqRcJw/WnY5Tdl+6e4QdwLt6g9ak7r0QHjBtJeRuzv4yfdnX5ZrhAoDjhSAlkyJv9nY5S9btRFFC5AVomgHk8Jb5ZLEWjzeJRkqisxHV66WPuoZNuHW7rApkcSvaj4WTvfHPWnwgoUepVft7rOsb9V2XxyerURSvCOthEzhHocZ1HYLJ7CTJtPSCpBFsH5Ei5DVr+qIczjGs13GMtWtNhlzbEq2VQcTsCl3oigW2OCgJM9A9hLVYZaA89NbuYu10zyo+rrePMwy8PtOZ22q6cj16Y5o7bIYmM9KN1PyBRRMZaX9WVultjmy3dahg7o1v8CakyIHfg0AlizbXvTttD+zLPEtVs01ZdXgZfG6BuJLa+MjH8y61rEbZSvxGIF+UMOb/Z6GSZX7p9L6Sb8UR3j5hy8HLpRzVv616Zh0WA6bzd5Ia5hdyVxddmRdAf8uC6G46ejLR2ygsctPvEICd//gIkPHwUOkhKXpMhNO7ahIcN+zXp9cl1tl6MQT37UXWqbpZbTbAOTxqrMi6UCWZVQmp0LmUN8lZm/ZpGCsBYyBmGOj970wOluuIapknGDBjPZKnVMnIBakS4GlCiqwNO2B9JgtwMEPqgkYetqhKqnG/ROB9dGFZlD6reY6iwSkwzomgPCu4Hftpiv3nkJpVUxWpBpiglG/DEsoFEkzUcia5blnyQVza6xWy/SUoxofKbfQOsuMq5Qr31FrXeA9l95Q/dv5a5WqSXhIVJ7titzARZcgLNYWt9f9BfQUbm9lbcxOq/T13x1UN1pvUIDOaNMOmcQLMxxx3eIqDj9rg3cWNKpLDjtg0Gkki+tiJvAJxavgpMTVzLAj8yH14BOEj7W6dAdaa1ixbJFi7zNvImwID2BFka7RjoFspuZmCnKJ/PhboIaRt1XsbSbJO3tWtr4voIjQci0Tw20Kswwn8fLRSjvZJDyK1Rl9y06p2wCeVt8wReHX4t2PXEDFDR9d1otZOXLP+KQQ0dOuxNygrBRgZmb0bnVBskqyTxw/JDaYFYPuexnin1yGKMUTLQ5eC44D4EIfx5PVaxOY6xFtUaZaVS44b4i0WBLw7Li7+C4syOabmwdwjPQHdv2WmT9LeuryGUTd/fzKmpLy/YfUnJ+hPiOICzRn8UBvyN9hTUgiACkrlW1X0sM26imBbxf+zjTYsdyNSDjzHb6BwCJUn+kqPNF/6/BKG0R3SGLSYg+0c8/iqk9/p+alp0LH0IytCqwedw+2ZvZqvIhNfpPuDd5OeEbR9l64=","layer_level":1},{"id":"d9c6c09f-4495-4230-aff6-8582fcde95a6","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"可视化展示","description":"data-profiling-visualization","prompt":"开发数据画像可视化展示文档,详细描述画像结果在用户界面中的呈现方式。说明趋势图、分布图、热力图等可视化组件的功能和使用方法。解释如何通过时间维度查看数据特征的变化趋势。描述多维度数据对比分析功能,如不同环境间的数据特征比较。说明可视化配置选项,包括图表类型选择、时间范围设置、指标筛选等。提供用户体验最佳实践,如如何快速识别数据异常。涵盖前端组件的技术实现细节,包括React组件结构和数据绑定机制。","parent_id":"43eef860-d2bc-4625-a145-101fca77c030","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityProfileServiceImpl.java,datavines-ui/src/view/Main/HomeDetail/Dashboard/index.tsx,datavines-ui/src/component/ContentLayout/index.tsx","gmt_create":"2025-12-25T23:42:15+08:00","gmt_modified":"2025-12-26T01:02:32+08:00","raw_data":"WikiEncrypted:YZI97ep9QXDPfRNDXs4+JByOAY7g5pvFXBR8+Ivn6oMmc/5gPhGC/j3TCYm0C7ADVPlWG31Q+6JjHqnX+jW0MtVvT+zz2dYtqKlKEe9XJOOCdl4EphFCI68rJegPRnok+i9NGKPJVOIdkJ5gACoCjqpRGuSwCalCzcN1+JMOpeisCAwDvXbPAbqbAcH7UoUn9xsqkDEyEywA5QS4ZzftITfqYhleFV/Xugc9bWSRwMo9wzpPyGwf3jzTUQLSXz30blb2/6CQkhxRnUy6Epce/0tEoGxGz2sqqpKdwwzVwBjSSTQMdTxNVvnmaGVPu1oaMS9/kg3nxdtEx4Yti4zSt7mgmyiBHN28hsTe4cY5rSjFo/jNEUoSgzeLHRkFIBlDNoeJYOVt/67WytAsQMoGDhZLqvIHfGRmc82jgjEcliK0l91WIK6wca17yaMxcrlPeem4rl4vcqaeJ7z30dtoYUr7ZQkX9n0KZHs0adaRkKGOuN/bWuiuc3R9hXW6i+DHXKFy0hc0yFO01n64Ve87xE8MY1uYcf6UowMK2BT/4RkO3OtLjavRmrFe4d2zBRV994H68c54W/w3XiDJfo/WHFrKPZXR4Frkoo4z7TFTkoF7u36bpGTz7zzME4e34vHzDujsRfPGk3i1Fm14qFTmotxPFJUzC6fCiTYencmkrNUTxs6z7scEHb75CFapZfPxSvgYD2NnS4z0DCVeDPyA5Ii1GrZPsN92DdL/c49UM/caWKm00i6iGzgok4QdHljfGkAt2hlUM20twZiNXtH3BBNrY2gd22InnuiDdOTcKn3PfY5bUf2A+dDcoeGwHORhF8joAtG9muAZBIegQDl3Oj8ZS+2JgG0l0Oh7FyaxCfB46BULxu/Lwk8V9Uc/80UbhkNcQx5ISzIhe1ZpnkqWjiAA/BkpNpQNzVj/cZ+XcsGL3YoZ8oD2Z8xR0vM/S1hcyxzcrMHRDdbY+1EblC9DuOeFUTmd2MdlDKdOz1Xwp3rAq9vrZlOyK/Y3oL3Cs0ydg+c+i+RBpf5d4W7MYq7XZ0cpsNa3ugi3OiVomUShfRqPqq3KLKJ7T6PEhT6N4zyD5PipAP7MsbGaZzoyUiSs9x4MQA+TkfjVZRLx5BxIs2FMtKuhQAvs5wJMpN+sWKEfMwVAWhPhjeLK2mqK43/nm4gFP/UavsrnFpNYwWDTHO2MTJ9olES8YweV3r5z76z8zbSkw6lXGpPDEC6yKvqypt4KqPzvvn7x84GtK3QU81iNH5r8NgrkL+hqZA47U8CKfqaNGQNKfF5llyM2OJoDBhoVNysBMUD6Vq2DdgL+4EF8Bdo0BvgrcG2NVnIKsriWPMgBhIV3u7VxnhdLhSzHvlRyH4l3zFcAi8/3yp7F3zdT3CHD5gIVCv9eAoWHqqdzVDe/EkXikL5mhV0XW5UgnKal1mTap0JmzpbrqUYlB3Q=","layer_level":2},{"id":"4fe521c8-eabe-4899-aa88-38fcb7db2d6f","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"系统启动流程","description":"startup-process","prompt":"完整解析DataVines系统启动流程。从DataVinesServer主类的main方法开始,描述Spring Application Context初始化过程,包括配置文件加载、Bean注入和AOP代理创建。重点分析服务注册与发现机制,如何通过Registry接口实现ZooKeeper或MySQL注册中心的自动注册。说明定时任务调度器(Quartz)的初始化过程,以及心跳检测线程的启动。通过调试日志和代码断点,追踪TokenManager的初始化时机和安全配置加载顺序。提供启动时序图,标注关键步骤的时间节点和依赖关系,帮助开发者理解系统启动过程中的关键检查点。","parent_id":"7b49efc1-5641-4ed2-84ce-ead796da0963","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/DataVinesServer.java,datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java,datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java","gmt_create":"2025-12-25T23:42:16+08:00","gmt_modified":"2025-12-26T01:03:30+08:00","raw_data":"WikiEncrypted:/1EPo8Nk1qNdA8r354IG68KVUYjq526XdmWelQMtpLowAd4J9sLJgi8t+G2YMG+pQNRfHqjgrCb/JsY1RpQT21EFR5RBJd1W8I0hjYYqdVWuglDJ3kG1QoyCR4lwM9W/6jwR7qjpKVGpkpCPCZdoCYS7cUl8poOVjEKN7/3gEivnNS4oQT0zffy6fjOxB0esG+4POV20a8lFPcXjfAIUWg8ie4+GYUtQXq924Mc0fU+hRDEDd2yS6SpCGXh+QSK9oqlOpwaljURBfyFQMi2KEt3NFb6cysSX0jaPeajVOVkG5DfslkWC7QgSgPBtIFbkXl7aHqloWjdgRy/+xwanVERLkm31aNQlLXFZij/vVQXC4j/K0yxC9GPX74mdJBijGvdZAxmn2Pbw+OWJcxAxMn0NCGYU1CI5VMYLNuEvwl5iM7eu7lpqtGPDRD6EXdYVdsKabqx7BqyWawLovV3PkULNockOdbs/vFyM0RUP8s7hwo2aTX9NLG7n4qtJgz+4c0dtVIMx/9uAv3+RWHUczplaOahTavI4AIMRCF0yqnLE8jV3//PKbrz14L7j6LPI0X75bwNrP9ZqqyZRBCLWlS7F4esHEWz8/79VdxE/GFcsNW9KYwwKyHKeIpHjPpMD++PW44XuGsJx3g/Q8q8ofj8p0wMe10tCiWF/94dXhOKbQVddQ2v+TfOiAieEHK57+/5S2ETTsoPAQ7RarFoRnWTFyXIEIQQUjCbzpY+lOX3q0ihOrqrd2YCy/zGseiXdweFbqK0SaEbnqsdQ1QGKV6U+vcMueg4wKZBGufVp81IzCBi6OCRfGaNAa+Mc1X/1k/M26K5GLgnOtLGGYcQ7uNusdImwix9nW1/zCviUq8t2j9QxBBkYSsVJNKoRSow5DRIyd2lfcHizJpXH3UThwaYqpbzmyccIIHokY+esKX/8Ai5TPy08G08hFeyNCv+mwbNqi/hkhZ1fYtH60iI8gN+iWY8qclKcRLInlz65rPscXLFMm+wfXnJDkskUP342ekojNhRwzUcDCFlkeyLc9CxVd1I4XjRFNeOAgK8mPPzNqZs6mxvaFfbXkWJupF79khlZrld0HdvLX3nFZchfmsX38kPLrN3BSJCHm718m0c2OIK1PjoNfvHWBbD7mrpvmlbTgdGBVtSKdfzY6cXbCnIrTdqeo4QpuKnUCKEScUqFNmPkHV9RmIm8Gcahz3f+OtVMikguhQYcCYasMJIRh0X4dgfp4h4KQIwGlPa/zH9HForliCOq9Rdp1bEutowEG4E/oTOOhosRU4/ZwOfNyQLkxIIOReqgcnEOpasoXG1R5bWDMfPOeVAdpY5xy3MEXaqXNxZWCrx1XCgBAflVXpEmyK8LnVPIPlt81Iepjg+wYkZPz0PX7uMxEA2Rh79cY5S9O9BNUlBXaltz/7TkVh9T3km8n9Vjgvk87EX+DWfa7m2e2y0h68MXj28oB6TPqhl41lvtyrUgXQq5q1hx4g3N1yidBV+fcSnVuhTWC4o1BhwdfV/uvryi4ASO0etSxuZEhixJ/xf2pIdSF7AVEQ==","layer_level":2},{"id":"89150110-41ce-4344-a684-350172827c8c","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"结果验证","description":"data-quality-validation","prompt":"开发数据质量结果验证文档,详细描述质量检查结果的验证、计算和评估机制。解释结果验证器(JobResultValidator)的工作原理和验证流程,包括实际值提取、预期值计算和结果比较。说明如何配置结果公式(如百分比、差异值、合格率等)来计算质量得分。详细描述预期值的多种计算方式,包括固定值、历史平均值(日均、周均、月均等)和目标表行数等。解释质量等级(如优秀、良好、一般、差)的划分标准和告警阈值设置。说明结果验证过程中的异常处理机制和容错策略。提供结果验证的性能优化建议,如如何减少重复计算、如何缓存历史数据等。涵盖结果验证的扩展性设计,支持自定义验证逻辑的实现方式。","parent_id":"a19e7b20-774f-4c69-a930-24d3fbcd2f0a","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/Percentage.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/Diff.java,datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java,datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java","gmt_create":"2025-12-25T23:42:18+08:00","gmt_modified":"2025-12-26T01:04:09+08:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"b5926d5f-dbeb-4d9e-a36e-cf98ac31d9de","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"插件开发指南","description":"plugin-development-guide","prompt":"编写全面的DataVines插件开发实践指南。以数据源插件、指标插件和告警通道插件为例,逐步演示从接口实现到服务注册的完整开发流程。详细说明如何创建插件实现类,实现相应的SPI接口(如Connector、SqlMetric、SlasHandlerPlugin)。指导开发者如何在META-INF/plugins目录下创建服务配置文件,并正确填写实现类的全限定名。解释插件参数配置的传递机制,以及如何在插件中读取和使用这些配置。提供单元测试和集成测试的最佳实践,确保插件的稳定性和兼容性。最后,介绍插件打包和部署的步骤,以及如何在DataVines环境中验证插件的正确加载和运行。","parent_id":"a8f7f5d5-bf23-426d-9273-02f47623381e","order":2,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/ConnectorFactory.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java,datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java","gmt_create":"2025-12-25T23:42:29+08:00","gmt_modified":"2025-12-26T01:04:03+08:00","raw_data":"WikiEncrypted:ukPV2tcWPRGn89Upsee0BCWcZvh30/9+V96rWvIvLQZQ5Dt2YjqkOzzX66AVXHHSyp0CmDhgsm2tyQQt45TiHv45+AvwLJh/FQBUiwmyS3afYm2vxg6A5VxHR6YsjbZNN0D4y6RkZySjaB3ITx7Jgn+PXa8kgOqMKJtdcJigC914Y6S8cj31lwyngrOFAaZK9TumtjL6LsPoaR1mWeDEdsQjh+1/DsZWnW9ZHnKnudk/Oaqzkv2oDPWdIfHaBVBhXlQfh9z+F6W0AIO8NP1264i1zfI4jLkIpy+peVg3WyFXnopzYTryUb0ix/L5qjkRhAJge4nYrr4hSf+XFsq9no0YoP55OVDVElzhG+XI6+WCoDglktmxoqN6K61sQsfg9/SetWxv5R3Hh2ND0Jltxze2mZ3KnT7MmzD/lpCNHlvGAKwK7OaA9NQoKiF8ZXDSjXQGR0g29b5tDuD2wuIi6Y1MHRlqgrqXSrx2rRdTTXk6SF4UMdtboIV0TCfNuefcW3mueu26iCecFb1foCs59NXIZrbgcqVkS/vfaes/Ddp2CCirj04k12/27faktLHNepmIeO6AdvJE8GSzN7eUvqBIxbYWvAhuLgvqd1BJTiCDvuOqcEj7UnrsnSw4PvfhxXVC/64rXvd1F71wVUkx0lCGBiYkumN6SqaKltwXN/B5nZbxRS3HoWWkMG5oswporFe+nCLdnQg1X3ClpHjq/XlZNkOnkHfdV4zKBBgpPnH4P7t1AgWlPJT1wyRA1AoTCU6V2Tc3YIObSPa6nd6ZoKeJzkcc/HB8KD82UAwGd3AUtcZo0VHI1vR66w3CBbzrQHcMkA9j5JeZUZvGhnfITD71i0uruvaBOAFVGhs/XimB/aAFC3xMq4RYoGGUmvVlwe2mbzFEkkkDdVeAlyWAp39ePJbtXShl6YRXRgoEbeaksRHRrMz3JmdYN+0NKw/L+4/52gLvxBG7DiQHZBi8FRb/OLfoOdsmhtwepAUeWRhB1sVICSdXMzop7TK7a8yPIFMWtOKrShGXpWYblt5QSJtU6isNtPN0iMXBDhOADVsBpFtq803fS4cMMLCSjp6DE5f+tPZLha8J/M4hAIMo+Ih7MM2Fqt58tn9Ihul45vawZ5M0ZPISP4s07i6VKMCs3P5bC1WyOep1xP8jALBrPVAr3rIArfvU0DMxxlPJeLVqyQ8x0P7syf2rgXdXlWLjbcRnYwmJIjBQ9Sm9AvOR3i9wsjJd8kiTLk0y7PQX3IfT6hBBGMDX6Xs8wAWSZnm0jM8/fRoOrvtb5Bo3tcUg4a+QzMxLbuBhcrSXDpcsWKPBKTEV11ISJVxmmC2oc3RzN2ugntBrvkhBy4UsmqhKTABwXMYZg6iT0LmHunUxneN5ZArIc5fDjy+K+wXFTHczbsNID3qn78FuZZg3ctE+xPG9qxyqTYolDWv96rxeNbuE9HeDVM5CrLceMJLpNWkx6K+o0suSga9IgrTXfgMQA9edXcCtiPvJTlSC8ll6BMpSFRstP0cwdcqz6gvwU3MvmEJoaSZ0n1nECD4/re80aEwa2q/8V0Kbq3IauYx9B0GPivRg5dBRrYwtXW7k+NnW7Mw+X467IiXpVGUBUFVuWgCTooRCB4E0QRpK+GL9PgF5FSU+8FHQ7RP6Cx/Gjxs/UblV4wUE0AmEMukCDeGosZaVGFYlbkMVP7Rn7iGf7zmnls6l7OvMGJZSJq8Pk76H","layer_level":2},{"id":"20510b1c-4941-42d9-b461-571abbf86340","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行引擎","description":"execution-engine","prompt":"开发DataVines执行引擎文档,详细描述任务执行的核心机制。解释EngineExecutor接口的设计理念和实现方式,分析AbstractEngineExecutor的抽象方法和模板模式应用。说明JobRunner如何协调执行器完成任务执行。描述执行引擎的资源管理和隔离机制。提供执行引擎的架构图和性能监控指标。讨论不同执行模式(本地、Yarn、Livy)的适配策略。","parent_id":"4e0ed203-0047-4f0e-b2d9-d7fa1cf34621","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/engine/EngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractEngineExecutor.java,datavines-runner/src/main/java/io/datavines/runner/JobRunner.java","gmt_create":"2025-12-25T23:42:30+08:00","gmt_modified":"2025-12-26T01:05:09+08:00","raw_data":"WikiEncrypted:jMgId5h0EoZtwilIIkOV3gGBpC1B3YEGQvLcrfhqq/8SYdYsHqyCisyE8stb75ccAv1TorJHjux9Pc104kzTUAIzleqy14a9h3e8DIwfbhxJefWqXD/hf9N4laBNQfrSZSjnN08ig7oeMA4EofLzhm8myF9o+Be16Tde+Zpg/WgpzAFzTze+3zJ1j0Sj3s+idn5Cqe2hAV9hqDzRbAzJo7IiJirURiOTljNxviu99E7pfP0Wds7iCimG0evhCS9zgsPxPKkkS2lUOIcklWSmggy5tCDc5tkIrs/HH/NzVojavihrw7fGbgjTiNKeaLwMos+mHYOhk4dfuN3A7ilUT611AiIds92FIv/85B/5cmWceJ7E/lbQ2bE3A4YHTqe0EhlTcMaK+2sHyRQKKYZuZT6Y0UO/l6rToQDY3OYv7B0jMzFHPSByAsINKlizM+XVlO8ScQx516cB1FfhrGws3zlmD/b3+0ClTv4ayguGyAEwpjyNw54X3FsTm0YD2cytMKxz0TYjsNBX6wSo9jUi3lGPB/4lI94L6Xr2huTGEm47kcBkvpWgsyD9Ty8qbmQQ26YZMm0Ksux+YR06IfhXPOfI42Jh1+orxwQ5WtKxjxNhbIc8846NRueu6T3yvb+xtIjpJ9f4WO2cFiBXl4UU5X7X81JWs8o7JqWOrXt7HSIFy5T9G0lhFv99S17wb42FZIxZgfM7SdPZvccIrzpApeNZFC8X6nuYyZGldC6Wslx+Qlyq9bRHbGAgL6Yxssh3N0yeTgoYTBn+XR738mf7zD3k6DOz4Xb61g5AyCZQno1hn+iPoOj6McIp2zkO+0lD14x/KfWraADYCdUxddmhtTQtzoPt7z7Wh23duO5Zb03ZYpEZc3gSiH5pkE1EITL5CikLJoQaE6+ObJhhRQ6RRm2altFd2MilJUUdfYTeHxbYf+Jirjg8Tk9L1eImOLQINpJIjb/W48WL8NGIRNjgc2gUnmBNhmKzRw10yU9Ej5IzechEroFI+OlTx/gyKNZ6BuPACHHkR7BbAR0HXcd0Fx4rWIvJX/ovWRawqHOLigIEJ9HCXAI+w1XbjIYJlQVZU9AjJ8djA9UJUKQd0gH91QjftmqzdLeHUPls7F5fhCcwlv6mEn+VXk/d4yfQ+4miKUjbScVJjuWb9ZydovcmyS2iBBP80XLpkVcnO2w6/zrQwG4wZHVQEoEEnup9yOPJeqIRuUXnUAXAPavNbcHeiadOVPtXfxab9iB8FIflwVgbeXpIkplkq2lgq6rUvh5y","layer_level":2},{"id":"14c3b8e9-25f1-4a3d-a52b-32127251a90e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"作业执行调度器","description":"job-execution-scheduler","prompt":"开发作业执行调度器文档,详细描述JobScheduler线程的工作机制。解释run方法中的主循环如何检查系统资源并获取待执行命令。说明getStartCommand和executeCommand如何与外部服务交互。分析executionOutOfThreshold方法的执行阈值控制逻辑。阐述RETRY_BACKOFF重试机制和异常处理策略。提供调度器性能监控和故障排查指南。","parent_id":"5856ff4f-874a-4522-87cb-4ec444ac1aaa","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java","gmt_create":"2025-12-25T23:42:43+08:00","gmt_modified":"2025-12-26T01:05:53+08:00","raw_data":"WikiEncrypted:yZ8o4WQI5gFnMpMgO6202VbkUBpM3aewiRHUr2gMLusFPD93kdH3OoNU/njk9rmDbyqHilIC21OAAXK9/GdV860wXzC+pJzrv6rms0OcXpRwJ5IrXPRbQFwEcyeZ2GgsP5U1MLG3ETqvMSFSeqv5vXlrYFWk8/zy8uMzg+ociERPBcfrn9bCyWGiVblgbMV+XdgShM07fKv5UBw39fDuj5fnlzkMXzzAUKsvIAbXopOwNPFBuiCCbH9uM/NMYDcdH/H4FycZK8Le5WLc+Mg+Wa2+Le03cpPppDFV5tw3lTDKX5IECzmGCgrqcrdNQa/iSWncmh6fVgbJlFnw19cyhWoZlmEbHrlsegU4GCLES5XqTFvSjV01UNKaL3ns1fI4o3mSt5xPP31t85NPHnbkfPsZK1WUkHHfTfiQBRStiOuFEd3VzqthmwSq4xtUlJtxWKo3nr4ec8J9CxMbizgNQCGqWhmd75ksVaHErIacbxVin+Et8vpRxr1eJVScspJLJWb4vW/pTcBAnxo0N7ihuKlmip3DDqW2dhdyeV2FJwKIYM6Cny5OY2ryUVArh0rxgPXxdZjFvXDCOsOeSWPQXxVAGZu9GB1hRHl2liMAn2TTsP56/Pui8HQObGBEGNqCcdsnmv9N0jurYoEMg5eT8xOan9QSMjaVbfsTqNFU64tGLdwZu/pIaO6dKXd8pAEWqISuvmGeT8VTkgS62oHRUQJG/q+KG1Tagoyfk/+R5hF8KkXMW65SinxR3oRaGmqa/b+Nqg2D9/dq3Ocqmsa5yiPsorBpuUgBKCUgyMQV6Aj6j2kxXVGwKP4C3CxwDpGEYnbKGUOuh/HQoZlezTB/PJ705W8/hL4jXgxK1A5RSkBaV+XYCsk7AAbanwjAsNDzmEtt48VqkydrLYvXnqI6Pg==","layer_level":2},{"id":"c1af4cbc-1bf5-4b48-bdd7-f6be8c87b776","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"MySQL实现","description":"mysql-implementation","prompt":"创建DataVines MySQL注册中心实现文档,详细描述基于MySQL数据库的服务注册与发现机制。解释MysqlRegistry如何通过数据库表存储服务实例信息。分析MysqlServerStateManager对服务状态的管理策略。说明RegistryLock和MysqlMutex分布式锁的实现原理和应用场景。描述心跳检测和故障剔除的数据库查询逻辑。提供MySQL存储方案的性能评估和高可用部署建议。","parent_id":"da4c595f-1508-456b-b54f-fd0b5324fa43","order":2,"progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java,datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlServerStateManager.java,datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/RegistryLock.java,datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java","gmt_create":"2025-12-25T23:42:58+08:00","gmt_modified":"2025-12-26T01:06:18+08:00","raw_data":"WikiEncrypted:jQUrujkvfnvWoK/AEAmZZP4sUTlJRjEzeQLUeUO9SlqliWbkrHFTlMt9uY+jsfYjOVWn+juIi+ExymTYaKgUln1wC7PEsMIc468LyelzXIYogCE7IwkLFzBh4qw1R5tQELWguU0QHqOKFu8kbzyFjJ0wyab4VRhQzFQxjaH8U/75zyUQQT46Qitj32UM89Rg+AASAzzV5Z2HOiqrv6RSiQcAye7zql3ir39oHE0XS/NaRWhkS9eIZ+fphkFf4NI9uuEOG2dv7dRJRz/qoiAC/cxqLNfXYttjU2Cgi/qVdtj2IPFDXZAUjekzutHbwQIfcGXQ/CT5CrtkpYP34Jl2WoIQd6rXp6utfznGQbqJzyoYXNksVtkgGKedDuodU4xxzDlF8/Mlwri8XiRoSzs9xyEVDDYkaVI/XImz40x6MBnvgG8YPVQTrmERoP5DdGBT4QWJjMolRBOQapJ7AzB/bBWCcyMeUoyOJrlW7kaXdXu0x3KdYCnlYX1RlevKEd5/jvjT5+g3swb0jL2Jh0EfUsHZcWf9nYZBhC1AChGyNFrYGO9DsBjBWyfZPKgUi7E7UkX5DyWrGMiSgN6WBVnJimk8NphYQo2GUQazuA2YgfOgOgZUEkmWfAr+KNy7AR9azjNyl5rUBDd00vLAaBFkkrZamf+TXjXv7Qg1SoO0/J8uQUoZcvrS2RIgqw4YyoLbzCtEI8XN++3ySx5PJZtnwnEZi2ncxTjod9GP4tir3BpW8Jv9+E3jb9wrx39aLz6CuM7VHt9rtPRPsozZ3tPfDfgnmnMuuy57WGGDAqzcxNTNkxk/IcXZvw2oHBq1iO3TBMLSUCcdnXy/b1sHaYFCDQuE9LjVJc6EJGc5/nag/4N320nnkQWAhkSWarnWNWqtTDTVaig6Mx0+3vhTlPv6cTjOaI6SEErw9LLpu9GM96taQwQW8JcOndap3MHA6o8C3ZdhshrHB+YbbjWWNNPMNSkkYcvEk+KG0Sf7LRzSZ915Il7SXGicxNWQze2rIUPdFHo2W8whL03CZWZlh1eZq+ZvH4pC3eohpcEGaS9sxnZJkpkW8kxbzvcFJBeI3Ia4tu7jlCMaakbgDsdVrnZORXLDxRQFsJ22Pa+/L/oLOCTgjoLSbUER19CdwhDuW2QvbqZByvtuhjXKptFNRuSlsw2BKkV4b/DIIeZSQuQJsfKsp1k+UxP+YbLdh/Kjujw8rVstffct07q0GpXV3OkJphdI5dlpKJ4sdRWG7ljcScdtJDs8mlszvV14tZ0Q+xMyHKr+mi+1CU8p7xK5QGqWrZyql7b66XWwr6AiGjM/9mppLIVx9sU5Rhy3n78W9ClGnO1WuK/oe43EuCI2jUI7B0jhx4hxZhBLp8ImLh2OLpvyqhlZCf2++ygw0GObNLLFQJWzoIol1vFXowsoSL6L/P6unD3V0tzYOqptBUtGtx3fHBCS0hCJmqbh7mjGB6GfE35vRpuJnLLNikakA7ugjqDG8k/EtQJjIKAMrbQe1Gwr0p94WtD5KTK+q0qD5qtAqWOimLoJie7RtAjpxmpw3b58ncRhVFRnd9ljWGTk/rA=","layer_level":2},{"id":"ae9c4797-fad2-4104-bb0e-09c584c89e78","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"服务层实现","description":"server-service","prompt":"创建datavines-server模块的服务层文档。详细描述Service接口和实现类的设计模式,重点分析JobService等核心服务的业务逻辑实现。解释MyBatis Plus的使用方式,包括Mapper接口、XML映射文件和CRUD操作的最佳实践。说明事务管理、异常处理和日志记录在服务层的实现。阐述领域模型(Entity)与数据库表的映射关系,以及服务层如何协调多个Mapper完成复杂业务操作。提供性能优化建议,如缓存策略、批量操作和查询优化。包含常见并发问题和解决方案。","parent_id":"6f063aa0-15d9-4271-80a9-edc58df4f3ac","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/service/JobService.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobServiceImpl.java,datavines-server/src/main/java/io/datavines/server/repository/mapper/JobMapper.java,datavines-server/src/main/resources/mapper/JobMapper.xml","gmt_create":"2025-12-25T23:43:03+08:00","gmt_modified":"2025-12-26T01:07:53+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjElpZGxb+n/pUb1P9bTe0MN303g/M3qh3KhtNWm2ETJsa+qwGLQkc8rjIjVD720jWI/3RjQp7c1JOkquuqVY5HT0MB8MzNZFCjW0USF6WuE8tjAkLW0fJdXxyM94Q/3geqy754W2pG6m7S+/cOmAe5H3wqCfpTV//Y/zgvNqeNrriUKtoYU7qUP+Vt1eIaipRiAYJXufQfVy9RMy71DOC798OxRE7pHFjD3nAMAy0DZmjOSaI8zivjKGJhA2ZF1bNc6i3+5qQK5p8G+Ru0Zr4hubsutC4DHb1HB1dB48DGwUA2vqb/lBuSa2xwcPkHTEN56EuaZkrUyeEhWo3oBL5Me/XIYfz6KM9AZEbnOcneEb5+JiRPOZOihmrZVfhe8E1kjFHWw/X3t92t/SZ7Zvx2WrkKlYnJETrIXe3FIOB8Ng1ZbGXRpY97GJyOJgiC6Pitd8YbdGubFUCPtfnZd20v0GJeflUj0quyprUfqiQ9nGnp8htFFjLJnr3gv36+ibkvK5/JptW8z3/gkRqSsFLY8uCzM9km/EaiqxbnQEGyjP6Pj1WpPVv+s5TdNbr9FUGJ2aO05ibPAn29tXA0uP2mDIzHUzNIuyN7LSfa4o8p6NdKStkhRU7Q9J2aYq7NQBdFVq5l9oQwf0htC+jXYqdwZC81sIlb40HBkYIlfGHk/vwEgHL/a19kPBQhObgBnstQkhw95HuNikYC8XYS9Q6qlAgBwHrsfFZogcAKitI8xoFX55aK3MS79vJD9ZdzYbCwKUirnT8LoUPbh44eHH58fAtKmEqnK+iGC5SGKZhwWZhY10wfzL09j8YKs5m1z7EQEH0Z9pzF7msLH+z+38etN/IWCGH6hOsMfzEM6DMhK144POnOdfrtzR34HUmtA9nHJTkch9twXQHFdqzkLKhzTCrJsLCfGic+f0uTfjxjYvzEi2eKCfyh2yNALcjuSX4m6pSwRZRGb/jqTl4konx725oJ0k/Wge7eSs0hqqusfD5QKt/vsb3SM/hZNwb7tax6JQXFMWFpl4tlfMkawo2lyUlSmCBT1WUz6kxDbKMSZilpKSWOqvPDHJ+jBvF/iFX/u2VGxs2c1eC8b7Qectji3d/4MZikzq1ocRjqRsxNw2j9tvdIjfDMgIjBmyNcd1QXMgiXsShhUwx6CLekQBP0LhvtECTSmwxLVwQ103Djq9spg/EF7OHNiAooq/QExjcu9255JNiuQgFu/y72h5yz2EBhCjU5FE0SaHFzbmpL2L2NHKWzCoLVHVBJ/El+FIDmzvDmQnAMbTE0fuzoxzpI9xzchlaINw+XSYBgp43PCt8rQIbyoO7I7fXVnwiyEwKHmbU6uk0S3F2rxv75p4jlNvwd+Y8U54k/Hlic8CBe+CO1u/FroaJVbuQv3PcwNV+p6D4NA0Gcr0KHw5Qa2jTFDo4ZRYr/X04hW8a6z2E21ZP8upSUkykqqQhoY+YaDWno34iQDk33MPNKzWlSXo8f4=","layer_level":2},{"id":"f053dc58-ea0f-45d1-ad5a-3a062ec4df4d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"作业配置构建","description":"engine-config","prompt":"创建作业配置构建系统的详细文档。详细说明JobConfigurationBuilder如何将高层业务逻辑转换为底层执行配置。解释BaseJobConfigurationBuilder提供的通用配置构建能力。阐述MetricParserUtils在度量指标解析中的作用机制。提供配置构建的完整流程图,包括参数验证、默认值填充和配置优化等步骤。包含自定义配置构建器的开发指南和最佳实践。","parent_id":"bdbc7ff1-6561-4953-bfe0-96e43c8b3e3b","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/JobConfigurationBuilder.java,datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/BaseJobConfigurationBuilder.java,datavines-engine/datavines-engine-config/src/main/java/io/datavines/engine/config/MetricParserUtils.java,datavines-engine/datavines-engine-config/README.md","gmt_create":"2025-12-25T23:43:15+08:00","gmt_modified":"2025-12-26T01:07:42+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJxK2m9XNBDIwakcKO64eeqVyr3PrfLoXTeS/K2VnEfAgl2GEIu7D86fhZ2V+Oni5HDm93A+GJOZhIDjnkvmsffSh95dKZC/z9eBGU7YrrN0LSOoy6ZtdmhcDF/1DsN0mFEPRp8lVMNiZFxK1f4eYGbOqcqlqcx/zoVMgLunTYqBwQsoyR/4GBIM/tmqAFkzIZzrD+1oJP8GTb8IaaDIQ5XjxtLtUN8+voRL7eh7I2Q7yI8MDKPQd5D8olbi4J0S/57JdFiXTaX6G0yMDY4GB1uyfRwfjXJDWUPQF3qg0XmUAeWaPCRmblybsl2faf5R5yIff5dtmBZqnik1nrOO3y+uFTBU6ffvLSeSzYv6/dfqNUF6hIIgJrwqlhsPXQAGoDErl5xJ5KoXx2++dsDFLqlbwe+x5o0btzSA5uSOy+ZP3TYJZD2AsQqBMMrbWQEsu7g31ZhQ9H9IMnIuM8ytI5tW1yb2OUZgGVaJyaDtLaBhgl5BuQC+IswWlnKBsnmh4L8DuSo+1FjwlAOTzRohVpR3Woa9FqVUhp6BAz4++BbtLHIF1CucaZEe93cc/oz8V0S8VD5oJ6QkJ7MeyrurOgeYnDuF3zKw8l4dlDaaV8fK1PfCzBGtlRCxKdvdqWBuBw4BnuCzlz1HwHte5LvkVAOcUkgrQQgRaDGvB1B43qGTK3yit45aVtVRtcOKmtIf2cKkK+Ay4BORh8jPLxFpxTT/Lc0FC2AOl2JR8tr43+H4B4zGAJW9wvDFfWDpmWK2gnlRU7jLHDrn7RGl1gJxcuZGdfI1ahwITztILWYrq7TYPj2CA98M5NvJCGSQ5zSuEzh3TvscrPu16kZIR7CVqiota1QNzT1+SX+0rUPSdIhL9uYwhVhUklpQ2KauRp7NFSpjYz0fv4zvVxS0TmycbwfBzPDO5VQDqnZB8Zd7tz1Zck0160MGUMyzN4kmm0Ydf+bU+SDOB5U6Hn9IR1hm71meOhdyXZvNCwck9gkpAT5UAZGuyO3vW/9avUt5CzW0Y7DmRCBVm2KUfcnIrmFOgT+qFnlfMy3quMdgfdy4iz53qBHXmmnbc6JgaUa8dusg1+agMUzf3Moa/SHdXvssFNyo7wjDh51lPJGoJxZs6FWA0adEPtzgShvS7909YgJMLf56Irmd2iuvLaDWBrLcPz0QhYQFewFxcpL+ljDlcIK+OYmuKzHGxiRt0wlgotUANKRVWrC29fnY6qTvjVZZbiUs259IFbX/7oE9cTg4AwnVS0Wyh3mVlfFLevg40tqzaN1B3JfkUbDel+suZyduGH7YWOezi3/EdIXTYbGV/170jen7YJ2+CY35mAkrRhYsgTWjuD6D5+VCdJQ15f7qKoER5sOCAY4Qg6wU7v+TdYOvx","layer_level":2},{"id":"05ecbf2d-dccc-446f-89d3-e1c48ba2e20a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"MySQL连接器","description":"mysql-connector","prompt":"创建MySQL连接器的详细文档。解释MysqlConnector对MySQL数据库的特定实现。详细描述MysqlDataSourceInfo如何处理MySQL特有的连接参数(如SSL配置、时区设置)。分析MysqlDialect对MySQL SQL语法和函数的适配策略。说明MySQL连接器的性能优化特性,如批量插入、流式查询等。提供MySQL连接参数配置的最佳实践和常见问题解决方案。","parent_id":"e4bd9d6a-26b3-44a7-957d-46e0c9ba5cd7","order":2,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java,datavines-connector/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDataSourceInfo.java,datavines-connector/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlDialect.java","gmt_create":"2025-12-25T23:43:22+08:00","gmt_modified":"2025-12-26T01:08:22+08:00","raw_data":"WikiEncrypted:jQUrujkvfnvWoK/AEAmZZChFCURHAokuhgBLmFbnuXQckbN6/lHk5XmbM6cqwkpRK50hy+1ODEZ8ToLX3uRpZ2m0IV0/efsa6u3NYrtreWCjMKIy5ygo9pYFnL/5QcOu+ha2/jxqdE4+yrRN6tcsxIYft/ih1nWyB3SvD5rg1pMVycOJR1UB8cMuWflT+JCyS+VO/r9BMD0GJoElYWt+rVNb7qwCmvaOriEQCIIP8oq7VKiQUwJ7vee257489yyKykLmEMkpzuFSd/YHjOREa60e7wmSXhyz76i9PBcAlIBclUpKKcz5FzyK7KeG2seWoBbPjh+kii1HModZYDckYKB6Ks5yPfHGVwXyIdYJeRWCLjFb+wrr4+dLmYWF/WDV9vE+7qwjcV65jnMKZ0Pv9nt1A+c9YYgssxW4qGmYjV6zaUE7hheSz2FI0fiIcxwXtL/ecrY5Fmiu9BxfImf4PJE0NzImPW26Oot8g2fBi2Ue4TZSxxcT5VZ9hIZWScQK/i7XjDSoDbnonC1Rl3pKgUF5RCi343EVmtg3AZbY97ElUdNBgZ5sfV2FVerkEu3wGLJI1itsDwE1t3+JbRyBw2G/uwqZ+L3OOGjMikbJ7D3fk4iyqtEs8kzhMLgsn6yZ9qM/it6xm9tvMZ6zl1hhnwlDINqFX5wv9KN0cyq8sERzDwsLqYP3TDj50eP29G+KrMKzSVQF5IsMP+vh3ah5CJ6H8z8F6pJYWNx5uOwonwpcB+2TEfK0zhE3EhiyCzG7AAw6gpow1LA9tZnVfDIxdwnCzsQ26tpW6mHH4I2dqkdaWsStbpOFRs8eHvTCZF1QP4SZVf+sFKV6I/G5NPtnIT2VGjenn+d7gwi0S2R6xzyv2jhPHtEBfJXuDwXtlHhcpGEEqIYvOKVxoirjAHeceQwsbNNf4MCZSPXFQph90aU4HeQE34iDpDBw/yQg/R0dgYSQzc+QQ7vQiOrr0gTkTe7BrtTuqoKUm/r3hCO1DCGNaG9yMax3X6fvYIV6xa6P/S/Z+evU1Nz0A9ayKdhvEKS0LPLEBlm5j2gt6ENGh3pOH9UGkHUw9/6NSLiAzaC6jfpCBphiOa2Q0APh41p9wN0IfYr3Kblxd9lrVuU4Fe/V7ufEUH5/45rjKuFQYK7Y+1ZdHe0P3VapIgAbu+PuxZzmugA34iwEjSpAFcI9gmguarONbESHFmE9yAbGBXt/uRFvRQXzIiIKeh2hbZz1J8Hj5heHHdL2R3dJJ2yHE1U=","layer_level":2},{"id":"a42f354b-55a2-4356-a7b4-d94e20a79fea","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"预期值计算系统","description":"expected-value-system","prompt":"创建预期值计算系统的详细文档。阐述预期值在数据质量验证中的核心作用,解释FixValue、DailyAvg、Last7DayAvg等策略的计算逻辑和适用场景。分析预期值插件的SPI机制和注册方式。详细说明TableTotalRows等特殊策略的实现原理。提供预期值配置的最佳实践和性能调优建议。包含多维度预期值组合使用的复杂案例分析。","parent_id":"706d1a2a-8449-48d8-8a21-58483495929a","order":2,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/FixValue.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/DailyAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java","gmt_create":"2025-12-25T23:43:30+08:00","gmt_modified":"2025-12-26T01:09:39+08:00","raw_data":"WikiEncrypted:mdJfD41XBk+D0hNH/bmf+sXrNJqX0xQr6lVigiXzghf/pCVoo3g99oluVtEXxc9CX/NcbHZHtz1PhIc5Xth1dsI9+fEjXXLnNdA7YYhacfR4caiKb6zgjcx4lmlfT5adkXWJ8m2iyA66F6Xh9gwR8+0bCjQ5tYso2/dk+8dGaBFa1/TLw4hIIP9C1pphLCEOXK4Ru9tMM8IFMsk2kCsGPv8H6WiN1rGljSbDpzL/AXkd75f/JPoAi2hFjAdkvjeYg9nkFwirH1Uyt37w93QGIEuFfjiLBW5TVt6AA1/d+wCw/vC1RtWOn9NuKGyX9JQsk/xkpP4OiJBCqUjKbDLBHoV6P5PPORO5LuG2D0VIstsT5u4gXRksb7PhCPfss5vxOVfnsb6Rzeiys5vbMPiMkGk8KYz1FBdUTkeSSXWHOB3vDD9VBnPPIAFNg4IhDA9NQsz2yvfh36oDz+BYDPiBLo37xF1wxk2IxwaUWX0yN6t3xpD54xG7H84yOvI5aUEklCczuVGiakNTXOkKTp8ijqMR0rtpNxW5FAcZoTyfVRezEECe2UxXwM3vT82b+iTukqc52H8FmstZHmYVs/OlkAARIqgKKcz8NU2sojpsXmMC+N6XMH4cga3nutgub/+LjRRMRTIFipWIvyL2H8WaRAwidBEx6xOT/eqB1U4qdV6G5rgbXRS3XRhkCzjVq5XEjayMlCilIXFZrsrpLZ+pf1WLZTRJmIMJwSDgdBFXMNOxFBj/YP7K1A7OnGfkMOJ1PffWEg09MAIbMWKHvRLc+StPh7icggQB/M8ikaGUotTAT0dHpzeb4hzOsUXVJZxCD6VwbF+WiOPaeMSIrF85kXqHBAxxLWcbFizwtXMB083VDyn07RS0NAWHDiJot8stv/Tofs/Ucg/Thukvi2SeUiPaiLJTBPtNnKPXSMOxtVK2jMyB6yXXOLjK/qla8evcoICePhZvqyREqONBdguVc+iaSRLFYWhGx44alC+c1YWZqn5BjQyH4ftN64/1WbwvbA7vHqNZEBh//Pt5GT34FwhKbpCEvGEpbSHOMLH4dqSfEFKvxQhd/nTAqceKsJbH43BSskjMjRfJplNLjDZCYM9RqPl+bwqhdPdfL23sjtEVvqnj1gh4FVXu++kRgXr4gPRiov85c6nrWihDx0Hdc+f8aEtwXegF9ErYHa3JbNRx8JGqR7hpRysDwKPiJLQdxROhXonwsv5nHe6VBwG2IQER3YkEkT8Db1/gawu9CWWjMgUlduvlCuUuYnQDy4pv9yE8yeMOSyeQvJDli36SfUjLrHgsZQih/nOqXXEqodonGqkvhV7YA3j820wf+uksAOXW+vQWU0EaFxLTu5WEOaD0dDYMzbSmRWwzgevP9XjEchwFAjm2wQ9vtLhYuQhD2QIJZPXAiDiuFFgWBiz6b9swO2+BlPBUoISI5l0bk9HGZ2Q06L2lpqwI54EUGJGCK7LueiR8mVaOsay67D7n6+3UqB2HcI6z565oGH8Wqvt+g0tTYKKTMHbJRpIzBrF1","layer_level":2},{"id":"24fbd35c-442c-4c05-bab5-c449e4e14720","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"MySQL注册中心","description":"mysql-registry","prompt":"开发MySQL注册中心实现的详细文档。详细解释MysqlRegistry类如何基于数据库实现服务注册与发现,包括心跳机制、租约管理和节点状态同步。阐述MysqlMutex和RegistryLock在分布式锁实现中的作用和原理。说明MySQL作为注册中心的特点、限制和最佳实践,提供数据库表结构说明和配置指南。","parent_id":"3d9880ab-c577-445c-bb52-b4ee5d0415a0","order":2,"progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java,datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlMutex.java,datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/RegistryLock.java","gmt_create":"2025-12-25T23:43:33+08:00","gmt_modified":"2025-12-26T01:10:15+08:00","raw_data":"WikiEncrypted:jQUrujkvfnvWoK/AEAmZZMXGLv1gTJH42BOw443j3xUDQSRg5g5424jriCuUt8dzQTEFvlnOa0vb/7k9FGQ+W5zDiCR514RJIHBDf+4TPiULE/FS7Z3gSONnCxR8yP/oH4g9jEIDUaDD8HkHXF8UHuRb/2Aiel3eSdnffqD4b0D1CW+dfzgT/l5QKSyltFKYWGYresQ5ybDt5TSMZSV7KxL53XHkYIAheOyptXaQkVjEnqe7Is4J17Z5ORmkUT09K3wD9nw68pWYgL5JXRGEd3O7mubRg700IoPU84Bq+qTCKIx128A59qMo+8D7X7ZIk0+5VyKs9qQcPd52BkQLqDNPw/oY/yDRo8nXJq0mygfqOD6kbxqKcm9ZIXkiEJVkZOlmsx0Fi4mmOmJE3PrOa9s9oYrZiFjD6zPtF75nfqjx7wK2NzcET//qRyMibzrz5lwcQqrFrDWJXrvpn9rZx2hJYajjrpsJPhNNHG7EwoqKnsuEtmfm6Yag+BIuxrU5Z0RpKPWJn69t2B7NYa+z2YF4kWHXZX8gVDjAg1Ud9FERyxxayDBuf+ZWeqJx/4ggDgp8ui3PkFlZCUxsya+dCIy5owkkYv75VFR4n+dW/DW2pgAw7QE+a9LxV2Ucjts5i3jovvP+cPEM7D3D6uXfVoREz1WWIh9+DdRQMzJnYNP2raMs4vAHVCyY+b2msWnc62CUANQtbhZ8UbhADJfuq7rP0ZcIwCSUBrpF/RaeSEPPYwaQsUu/BjE+Tt5Fpqcj5Zbq7Df66JfQ4x0EoBp3wlFW95o4LzsKCoUazadMQrOJKBHgi1T69nXfWAYAh9r6fr+RUchwZ0mwWa2Uom+qNodExOkQHSRMCFsjwmV+XKDUuxOObnxbIljpwHcu8VXxQTipZFuYG3PS0oBIIcP7H03YA18kSQFIzjKyukSHgf2EGJeUt1D32RAddRJivMI54SiQZCFwZ9v+ZA9bPNx83xbjtdNm+cSKC0R/3SBoQoCc0h0KwuRKz5W9C+ZFZBSFaafSbPDY4/tnuKNoXvHCMBym5NTWzB6UQyCpiIM/DHbWK01DohjV7uwemjn8Dc4Q3b5P1McVJkNpHJ3+0rrtX2dhpTERDVgD5waq9hFc3GhjXQhgpTN2kOqAI5K3PUVwcDw8CB/Okt9oomiDg8WF8CVnu/DjXA7ks9IIMPhIiDfzxVSAzBpb5vUSL42fl3vADfIP56BPMGmi3dDhGKSwUrLgOEsN99jnt8n3MEp7M9T0AbB/NF1lCge4p1A+R+zM","layer_level":2},{"id":"98e83c1d-0132-4fc2-97bf-3a05405fba4d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"邮件通知","description":"email-notification","prompt":"创建邮件通知插件的详细文档。解释EmailSlasHandlerPlugin如何集成到通知系统中,处理SLA告警并调用邮件发送功能。详细描述EMailSender的实现,包括JavaMail API的使用、SMTP服务器配置、邮件内容(HTML/文本)构建和附件处理。分析NotificationConfig配置实体,涵盖SMTP主机、端口、认证信息、发件人/收件人列表等关键参数。提供邮件模板配置、SSL/TLS安全连接设置和实际使用示例,以及邮件发送失败的常见原因和解决方案。","parent_id":"9b0e5495-2217-4011-bc46-1d550de3afd9","order":2,"progress_status":"completed","dependent_files":"datavines-notification/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java,datavines-notification/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EMailSender.java,datavines-notification/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/entity/NotificationConfig.java","gmt_create":"2025-12-25T23:43:41+08:00","gmt_modified":"2025-12-26T01:09:37+08:00","raw_data":"WikiEncrypted:/tgmwByRb9hMFGCVx/eV981fHmn+PvvP91Ml7fjHbUKa7XlHFS23r5mFmqbgll05N9FfLIRbeHoZ/3HgHkaPUBss1AuG5u/xcntI4LZp9hongEaO66nZtdS90MbbDfLVf/1+NJbnUpsmMsVh1rf1p4L4hxWJWwirZvA3NLrGliX3GriloaERHbGES4ugkCME4kBFXjTSSF4wxqNMhWa8/995IgoGyr58dWHHmu7Yo4K9VGQ61tmkEKPEoZdlnU/v6NKBczzAJ26lj7DsVZtQo6LFUrIJk7Idu6In4iDXs3QDMNAzO/17AfxbuYwouaExQfeVqP5mO4ipSxLImOTpNujmdJ/WbV7U09TJO/tu3oQOuWWLvWjocSIhRj8/tn2dFeyRttChjFyUQX0WNS9pZPMZtTESzInifs7DWb3bSBSxjMNRjkizpIFLhIsDyrnxDaCq7IQWOCTOKzZN0SOFIB//Clz6NAibxyYKiXdRD0Ezay4VSqFojNfI71Jvk73pQEyDeHDBGLGlaxEVsV5ghVGyBoW99IRvkVGmss8i0pqx0h0Paw4WsLXBZfEoY5jMYTkIhIsGOj/YCHR8OUUyYKie5BRzFDputIZ/VdVO7hKKN2lH7nul4e0Oj/sx2Y+Umz8V8pzXg37qhrMYLn3naIWFTPtU3Wcg/zwRMb9TpDkbBcOFbzOAz9i/xbfMWxLLJvBWSnaB4bNEu0zGvNHorb6kyToHlyHQ+Mjx5ZMMiTtsQCmmxO9ZjfczSGgA7F7ZwqvvZPPhLaOA297IcMfP6u7oLYQEPmhrL/kZHBKt64eOV9p+1muAEY4OBbSsLZCB7drE2kxa0Hj56mYbMtUTxuK7/I0pqgUtFwxM+PJkd/pAoiTHWTnEbkDr0h9sjY9N/sn+9S4JCguDC0wpA2SZH1P4Cd3fKpf/f+YycujbquQD/keEGpMGOszo/lg1OyBEu/eRMmfSIkaQDxIri1cp9a+yZqZdiki5Fu3nvi4V5DAjWF0DbNSNFPyc6OBVxeRkws44dkAv6gch/Kszbc7w8zEZ6zj1ZVD5esSnecNUBEK16z0rnv2pwP8CI17kl4Gp0Lt4IfOdQIx9s9rq5p05t0ik+C+Uq8WXUf74S5XbtX3UeWbpflPOwai5ZPZ/6tgodOV88oTcYS4vGQBdvh9ud8lFBH1Kz26Gewe/nEuR2g2GTS32O7ryKwSjQdOWTH38iNaUzurDGiwFe0IDNrTrlFaGvcBYKn6EffYFlovCdfeH5bVEGwaZa72yihOHsnGmPH7o7E5wGPRDCctWeBHkwPYi2O/+ZAhPENafry7+j/f6wfuQVaSp+UoXV2OMx9Xi26oI1e70mbidQOa+G4IzziuRdnRKRRU17JbrlXLPGhNbQZeZRTLQqZPeC47PSIQn9s8sy5SQy8PootbfxYyo0XKgzRv0F2RcKJpLcKi0TC3WugjxgzrwkbNBU97yxfbqwE0QB6Xt0j27rwH5zc8UAxdXmcuTQl2aCteL870v6dt4z+h3G4ZXCMl/CuGYNdMNgStOtChWObsaGEfEO5ucTX0dnB8c2ZOZAA8ciVh6ZSU=","layer_level":2},{"id":"ac71af63-8b30-47c9-a170-1572ee4b31d8","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务执行API","description":"job-execution-api","prompt":"创建任务执行API的详细文档,全面记录与质量检查任务执行过程监控相关的RESTful接口。详细描述启动任务执行、查询执行实例、获取执行日志、查看执行结果和检查详情的API端点,包括HTTP方法、URL路径、请求参数和响应结构。文档化执行结果的完整JSON结构,涵盖执行状态、开始时间、结束时间、持续时间、检查结果、错误信息等核心字段。提供执行结果分页查询、按状态过滤、按时间范围查询等高级查询功能的使用示例。解释执行状态机的转换逻辑,包括成功、失败、运行中、取消等状态的API表示和处理方式。包含执行日志流式获取、大结果集处理等性能优化建议,以及常见错误码和解决方案。","parent_id":"13e13644-8e2f-4f5f-aa08-89d3878d5113","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionVO.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionCheckResultVO.java","gmt_create":"2025-12-25T23:43:52+08:00","gmt_modified":"2025-12-26T01:10:50+08:00","raw_data":"WikiEncrypted:yZ8o4WQI5gFnMpMgO6202ahRz4ZYHU4kzuOmxISNJDXcC0V1AbCgk4tbNZ0r209P7KWZGbRiU+20Rx7sAtKfgSqOIzRoUw5hgW45rq8z3WSpY+z23S+5gP8OclP1ZIOfaK5CByw+3FEe2ROGQK+tgN1OttPybC0gNPDZHQklqS+KnegqN6E1u28uU9qLc9VcOHu72jojkxYwPhKUNqj5yMVohzEUc4il6AkKoVSoWZyRA/CnAfAoBT+zvtIE6SjanyLOTK0+IUfaO7Dtb6cPVn79kB9OdMQns4g27V7CkpCEcPFTR6ogzmTx4oIS6upaLSkkXlbREK6lg5Bxx/SwYGPKCn+euVE1Ds9EU7GQ7zNEPeXrTnPtQ1haiy32TkjAfFpnRzihottbHW6mKL1jC61qzyINiRYH4KMj9vByBGLaVTUnR+aEol8bYvL3iDBq2nZld+ns35hfxC5bvjg2M5YwwkjPVve4p4ZpRV39UIA96jNlsFdYWFJJwlhY5G87TPNRuka/DcVqkWcvdVvTa66k+duDuQoNDuzzkf9Munp6bNuDO6Rm2WAXwM0h/HnNEU7ijGsH1WNmmerHZVvQwe11bOji8acVuNnSKOJNbFbgBtpCPNEDK9O8DqykUj8nDBmETdnxkrgTIacjH5gptLQ7ez1a9rh8IoBzMOZS/c8ryunbXDkdhj1b8V7l6vda2YQFSqLBjQyQqHqVYg/6nLxRLj0S/W1RPCux9glR0RgFysBjrDnERArf+P2Qui4jMIalx/3Hq70lwfKjsl40Vqd9c3qgIP5ATT3kdl51qnfcca4aL7dDO0HekDzLqdIz243nIzjFLZJGkEAVmmbB1d2YKqa+rwhaMzdVjBUUHnCb5oqA0ZI/UfUryojmsogqF0QwcHmoQwYo0YvXe6Sit10yq2wcZ5L2t6zd2GhruZx1JlmrviqXRt2Pd3ctpaEdu+WQEhzWfZ9bwEdLQjSx6sWbcmNbtgGJqRpkrPcB69BbqNtrqcAWcYrrwfQeMuJcdYiaQv8laFBkJ4HVXYQChGTVtS32ffEt/2J8uE6cr1TpSefPzg15/4xEnFQ4vEQVb+8ScnGbWw0WB8vlgAaugpwF2aXt9m5BRRxc44P8Y5f2q6Z5YziZ4f7wMst2ciFQ1m0nIga9NFe/xqz9s21dCDQ4KDaSBUUKFnac5JMpUebCgyM/Tix3iBEf9oOLIFdBWeZtgtfe+oWzYEikeHtgXyaytv/Dn74BeubWtW/yNt+W9FHiZyS2qzu30sey5ZOqWgMVwjgLrztEqOlAinTnJyb+C+eq3eR6YSfQ6hmzFmRgWUpEYTogKTyAyloORTKCNx7hcmHbZs1K+efHj+jRkX5iIxo/NJ41z56P1+Dg4RILWowDJ/TZObYL42e1b6c8vCqWKY2yFUMrJbwoDqbkwLuMBk+GL/wcmal25Y/n+Vuc2+2YAHV1k0oQnQBmLcUHxGuED3Oy7Ot2TRQvdn5R30CZZjs+fYy2esxnEZyHz2uf/acnb+g+x/JepA8M3wG4aNefJkLIqZAq8T53vbFJkIVI0tBsEslJs52KSqErmDA95Nng5Fgv93wERX3KZsOcqGtgoaMOPVXzgEv3POnxDJpzYqtdnofL2RuDz5IggD/99bmfyR5fYoyoVCicd5OabkV242yEklhmiMq4rHXp2s7n2/ZNKEqy9p3ze+/wTCg4yBu+ipruoSWstUrGVX0myewjTu+JGHlEZnEG/S7Ly+/nCk+KAeopVuXCsdTRf7aGD6BCOeroha72kuTTg4UekbDw+4djKvkoOPWYIPtUVqzEusLiTSsh6VjdgLjdtGAZWv4Zo36Gu/hut1Pln3Io","layer_level":2},{"id":"29fa1aa5-5021-44cf-b284-95390545e925","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"UI组件系统","description":"ui-components","prompt":"创建UI组件系统的详细文档。重点描述导航菜单、页头、搜索表单、标题栏等核心组件的设计与实现。解释组件的props接口、事件处理和样式定制方法。分析高阶组件如KeepAlive的实现原理和使用场景。提供组件复用的最佳实践和自定义组件开发指南。包含组件测试策略和性能优化建议。","parent_id":"f6fd9d61-f5fe-4cee-a269-b29ba2583618","order":2,"progress_status":"completed","dependent_files":"datavines-ui/src/component/Menu/MenuAside/index.tsx,datavines-ui/src/component/Header/index.tsx,datavines-ui/src/component/SearchForm/index.tsx,datavines-ui/src/component/Title/index.tsx,datavines-ui/src/component/KeepAlive.tsx","gmt_create":"2025-12-25T23:43:54+08:00","gmt_modified":"2025-12-26T01:10:59+08:00","raw_data":"WikiEncrypted:olAPfnTddGwpj/UgpBjR2+Msft6uTT20LZDm0DpzpfU8D99q6PIVgbsT3DYteIEiyE4P/WVTnuQkBHMVVmKyuxJf2SnOIDKOzCwHTmFo5QhqAcMvqzQkfDqSDEh3c/Rrxz3b4qA0el/Zv4rVyUbl76NDWx2rFqR1+Xjcx0IFHU9v7dcSF5pdC5PjyyVQaWUcjLDL1mXsPMHpHYsWGa3NDIs55byDNVENJpIVCFJAgMjTYbrJ4pGPqW8s5bwG8VglX489YgdAxrW+hLOWiUz6FXVe746BQ4ztfsZfZKqK7ro24NT3xuEAxAOlR57Lj5fpLgygzO0siRtEehKtWVGq2LXWxazD26UcSqyKuKaGM+y3dGKivgDekZ2nrO5IFFdVmHf227G6BssiRd0nO/0HLpaUz4R+Arj3TwTKPfPisiSRbEYuD4t5AFaacdmY0AuFqla8opxx30r/cSmn6DqruXWxXOXhgWHlb1z/BNFYcI7nNFIk8LdL3QbbA0it4O2Pmpxq0xC20NLWbNVc5Gos3yaua9uUTgCmcxVtu8EMtbnEU/+aRWyLQ1hbtnhAOtOZGJOSwL8tcfnafW2b5wP6dFc4y0SzBd3MQyuWLAzFe1joKRiuRj4Aq7NkRVe2ZvRusOeBmx5uuZ4HXsejBCa6Gm3QVqt1YUHD8mAsaHLOUtanW8hssr646Nxt9iX5cgB4OcEv8RCXSRJSwDREAfQVWRtEsHx0OeKEDJS14mcBm+ag6R1x5AmS25IbnKQskWo9U3Z7E9l52Zqg85ztYLMRW3v32rPvO7xzIT/IuvzCpq+Hma4+KjvThUqf6JjLDsAfZB80GxQehPkN/N9HcLq1xd85yQiLgN1V5l5Qf1fDugE2ZMZeqQbD3jLrf31AhCoEQaxl8KnGAyZhPpW4zDYPde4dNXlS7rR5AQX5uZvlkF7LvUqvJkCn1sWDt2IOZV+s6F0qiqeFa3k04pap4Uoie/Q5SPz3C4pLdBCVuRd1Cm+nEEnb9SfA0jvD4S9Za6FRvHdmuO1qrwywTZ44qlUuGmbJMJIweW4kYUshMVgVoDos5MHX4awCAvbrb7pcFvaviB/pfz+IwZ8sDagErgqCKw==","layer_level":2},{"id":"a58aff9a-6399-4a0a-b4e7-b2b41a7deea0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务执行表 (job_execution)","description":"job-execution-table","prompt":"详细文档化job_execution表的结构。提供完整的字段列表,包括execution_id、job_id、submit_time、start_time、end_time、status、execute_platform等字段的数据类型和说明。解释每个字段的业务含义,如status字段表示执行状态(成功、失败、运行中等),execute_platform字段表示执行引擎(Spark、Flink等)。说明表的设计考虑,如记录详细的执行时间戳用于性能分析,使用外部ID关联执行引擎的任务ID。文档化该表与job表的关联关系,以及其在任务调度和监控中的核心作用。","parent_id":"3c7fa525-a12b-4451-8146-b1bcfafe2f1e","order":2,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java","gmt_create":"2025-12-25T23:43:58+08:00","gmt_modified":"2025-12-26T01:12:29+08:00","raw_data":"WikiEncrypted:yZ8o4WQI5gFnMpMgO6202T1emu2XeFqZjlMFbJ+5dlgJYeMFkAgG+OhmYErWKMc9iNaZdowZhQ/JVWBKsUByldhQuKgBVsw0cmHIH0BALPUfj1ojAa6rIJqTewRqx0teQxBOMcXsAsBaG0DaBzTVA4j3Xi6X4iFxzNoSFJPUl+Bt/5+6IZCysQxjDGENOD+PBUpdPFtgaX1cWD8L9PIf8jOixAV4CFWKsBaRwsHDvGFUYzHe8csOFgyLhOZDOuC9UZ6/YoD1d5kWgiPK5DAiYvVhStq3U69DlrDq1mnAniQIzfOP6IoiS8ik1UV8ySsYrVIBzw4uzi1lh/MaiYjR0y+EwlPhNizSs3ii+VCGx/+W8EXMfr+urtHAsigEqfgkSXHQaJd+xUrGF8a5heR/jJE4NX9fzYgbAzLfYgN2W0kV+bu6hPM1Y2BimTG2pCX6Fv8/7n4d3VABlVAH8I1E3p7kzwADblQa8FN+7ZkVBaMFEGkPjp2yjvmuhOLIwRw3yaPiqipgE0QpRhPZAYY+nd/vHHzf4dCuSusmUC+rVSWsuHVSV0fGYlQb+/rOECtQEklYztNfV0FDg8CdxX95mF7LNmJ2iN7yjUtymARWQKXm5Tf0PZzjS1SvJub6XHGJL8MBpT3RQMpheLPqzwzcNMfZWkmqr+TiFX5DMyV1MavKQjgWznQDdTD+PV70ucklDYCx1E5NNUfxWpwcLJatkI/VtZmRHfnerQ8DyzIzdbWz3lN3dUEVVKqfFz98qhYb03bWGrWvZnF337PB3S4AweHhyxYa4xtw+rvrz7b/eMiIEoRMKnW9J7kvyxuwdYGgMMrUJrrkUnMZV0XqZvSWsf48cE90qSwTMpbYiNvl1C9vlTm9JP9mw9qfOf0HBscf1bc49Tfz7trOoMgHgq2ZipHbtkM5Cq8eDCrWheNpx1+TqdcdqdqZPetk4QCAZY/gIeS5mAo06H7qt1+2Q+AgUkaxWr4RgMQDyGdw7a6DWk0bg+4VQjiC+NuBlqqXMdWbJBopScADTsQlCwo7SLs3SL1c5PuTBMmag9Xg9eGMmgPrtMcZBgPPJNaTvLTBs8bKbFCQlH8nSbu6wJMfifzNQb9sYkj/LOTSjpvMpfRraG5YxR4Vmto/V62Ki2dHnZpvpDcE4JPoHUD2KhuFRNm2fmROBRsJXEWiJcqEa8XIRmrJLs8gOBvomztJvjX3qT58CzGb1B6eW+tI19Vgec0r166J3FYTRGdN4W62Ok1TlPNBFEV9W6AwNL7E2AMAzEkz","layer_level":2},{"id":"7bd2f784-7e4f-47a3-858c-5949004f1d3c","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"元数据查询","description":"metadata-query","prompt":"开发元数据查询功能文档,详细解释CatalogController中提供的查询接口,包括按名称、标签、分类等条件检索元数据。说明查询API的参数设置、过滤条件和排序规则,提供完整的请求示例。阐述查询性能优化策略,如索引使用、分页处理等。描述高级查询功能,如模糊搜索、组合条件查询等。解释查询结果的结构和字段含义。提供查询性能监控和调优建议。解决常见问题,如查询超时、结果不准确等。","parent_id":"493d76ff-0c76-4864-9a2e-0a1aad23f133","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java,datavines-server/src/main/java/io/datavines/server/repository/mapper/CatalogEntityInstanceMapper.java,datavines-server/src/main/resources/mapper/CatalogEntityInstanceMapper.xml","gmt_create":"2025-12-25T23:44:08+08:00","gmt_modified":"2025-12-26T02:07:59+08:00","raw_data":"WikiEncrypted:pjGuIDHO+JzqEKf2Vs2HOiOCfWnElxzl1jZ4DdQcOO38m+cKYKABUe9J0fpdwZ6ONfko3IaJih9ShO5NWQM+oam+e8A9TALZo5spVs0P6GHB0xdJ/qBrhOXw7FLt67OmuxyteacnJwA8iKrU3Bz2j7W2y+RcDb7OkycoplrcKJcW9fqrnKOrIK4fHhCdqU7Kp9rw1/YuPC2MyF5G9w09+TsEoLnSoKxl+68SpKDgPZq8bFaUhLkAxu9lBdQ+9p4SMa3izehRmKndRnqOxHU6hjI2RSbMjc0ciohZBMDFVe9V1CktWTHvTyd26HnEgqwRX6anpQoac+pl71Y9dLDW48jvNUYZg3m2oLFosD0rb6+vxn0UNQ8bR73rAZvvZXoBzey+QOEYI98RWSurM1Fgfw0Dy+b4nCHwyfGZUGRYkQ1backfYl36/I3N+6a8a7B/b7U1r+WXNH0pYO9HnhYQsT7jWbRoT9/0s12aBDGG91al1TxXFOxZ10b8dkFUlb4KEMmQkYQ6froPI4mxAOGA2FEridod36/CUM4mvLaX9YuJXkuA0A7Lm+FeLrymceTxRDJXof54cUzzMH0iN/U3LquoCb62tuhg22lkeN7TsGYBF+PaKDBdy7F+eMZog33ypKWCkP+raqJR37OJdb4O2EfiHTt+MFS2GK+TMzyWwYakjZ55c79x9acOV67ILJnnC1LOqcWfO051DEBNmNfmiVi64Lnfkl48D6tIBV1kQZg3XNgGt/wo1c0IRcF8TBNfQK8CFzkw8PJhUJI6xVlWf395qr4OfbwqFKde6gfaVLNPwW+2Slntgzx4zFofGm+0m4w8UYY1GpbvdNGxN/0+z1Xp2p4a5SpIVm91x4MnVNXIGQKxN+0DnXIShMGl+9NDYvsmpAgMctKGdhfkbPE0VSLq9KgSBuKsIKy//TX+GDV+EV4eSF5VOTT1ljTJdHVgkw7HkKkEB/4fZHNgDuwAslV6ZVYxUTN8qPXk4y6Dab4GYgZCry1aPgAibcdzeRIsoJmwvF+G6z8qDxsY3/j3IaF0kjHsfFBpGYTPYM00fOT6Bb7CJM1KZVmfW0/KzkEEAOonMll3Rn8ZGoxaNHuJnAHHkaQKb9kNCNlBc94hfh8GBTLb4mPahG4UO9ojomu9TWReNjNRLCIydGaktr7eOVh3cWWb8aHmxfUfm6JbcjkzZTOebwfkVDt4aJ6VNEVKLA3ztyzRbeVPmRsx1t1v7q4THDQ+SbxTxl7NhaID9eNkRLjaMmfq/gMzge3YhimcFtvgOR2PEoMB26A0zQXCwV+HI/cSaNwSJjAXPdSCVP+A//GMvmrJnUN738dxjxeUR7CyWMIHvj0eCBt8V4Vl43+D3vs16ZHTMqbEDEiDnRE=","layer_level":3},{"id":"791a766b-a5c3-4467-b7b9-b5e08e90ab3a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"影响分析","description":"impact-analysis","prompt":"开发影响分析功能文档,详细解释DataVines中变更影响分析的实现机制。描述如何利用CatalogEntityRel关系表构建数据血缘图谱,分析变更对下游数据表、数据质量任务等的影响范围。说明影响分析的触发时机和执行流程,包括实时分析和批量分析两种模式。阐述影响严重程度的评估标准和可视化展示方式。提供影响分析结果的导出和报告功能说明。解决常见问题,如血缘关系不完整、影响范围误判等。","parent_id":"586fb977-73cd-4d21-81a4-ecfb619947f0","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityRel.java,datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogEntityInstance.java","gmt_create":"2025-12-25T23:44:09+08:00","gmt_modified":"2025-12-26T02:09:09+08:00","raw_data":"WikiEncrypted:rKvvwiWm5N56lB2P9FTYZXIwf0Wolv+bLV/hpJlHmukTop+JGns9uCpPlYsd6QCPosdeQCZFl9B5XjtnqlAA58Ue5Y53Ip/8gWQrBop860yFws8xqd/XDD3jzMcM+/gk2OfhP2tE5/IebGWkeKSeTX97b/IdhVpVci2BihmMScSi2nnRylOzacpFe8nys5Q9Hy6PC5/T4RES8sqFl04mgXcBVg5BZu3Tt4DXDq/qVosT7Yo8nz/c5iCJVzav56rjqDdz8OphctQALpsFy2bwMzRGyCs5L1h532RDmZAiQo1WZiK7JrF4p3Va/T9HzZ3SBAoWOGBAsKa6+Ec8s1wEeeuXHS6UFrpp3UGTeUrA/l3dA9qIRn/l54kReDWj/rphxorfk+cYAxE3XwAm5RwP7xlNePU/XlZg3J8GM53kMVi7J4SNdCjc9HY97KZleZGmBAzBRo8XEstE1xpOS1E84BEyojjKlwPHnG2F9lSCEx2mwzGNoSlJCe0WILnnQ+S+6qn6vHC92xcnLMj9CS/X3FiiuMawZfxDUBBHe7Su5NoXgqwzPOWbm7mZ7H6g8rhKJwRXf9h4hBo2EJR8MG1C9JXKM7KOh7wcGbTvBFqPaHZ8GDDEvoATICqdw9XHeC9R3peQP0cqgTawomqdnfj2FDcmrQzxSSpgc4NLyewfWC5TFrogHyy9hSJgKqyvN4G9CgGY9hP8TvIIeWRdHX5ikAjgp8TKe7D6U23aJ43J5DCXXXsIVCf1ooForLZTnSN77PB4UB64kP4sOJXHylGbZk7B906HxvPen6kdWh1vliraa4RKNqnqfsTZXzVdvwyD9AwmX/e1BcISRDLyhFljqfy/lq+jaTzArlw11AFKF2AjW/k0zfxrB3kg1YuMnvUF9SYGvIImbyPBeql5tGgijHULY6jBLBt/CWw4AhYdTfhS1BE9RB34FjYf3m7nDR3IBFwHm3ehv6LpOqBT4cTGnGTsYsZ8WGOm1+Z9KsLag7QYbSjZbt/u/2wLzAQTk4bEAjWXmWYZ5lv//xUNz9hWHdKvMz/9Fm+uHcFveBF+MiXH/W/ModDTFT8AeCsE2caCpNVDLI/2KJzPENhzJ4ndCj+UgcLopL3YBqjhTM2BOhE26ocGPtZWKSJsxM8X5yVEany/3/WH7Gy7yRg4IWZCaVl9eW2Hf1W4Jogqn4/lM9WepoY1hNWD//T1dLra5+Yt41U2niUSgYA806IicDpXINoPOgnhfi5n0ZlS6ChOo3E=","layer_level":3},{"id":"3810450a-d4ff-4879-8549-08ed1954e893","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"日志配置","description":"server-logging-configuration","prompt":"创建DataVines服务器日志配置文档,详细说明日志系统的配置和使用。包括logback.xml的配置结构、日志级别设置、日志文件滚动策略、日志输出格式等。解释如何配置不同模块的日志输出,特别是作业执行日志和服务器运行日志的分离。说明敏感信息过滤机制(如密码脱敏)的实现和配置方法,以及如何通过日志进行问题排查和系统监控。","parent_id":"d6d39194-b46b-450a-9e23-15374a060630","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/resources/server-logback.xml,datavines-common/src/main/java/io/datavines/common/log/JobExecutionLogFilter.java,datavines-common/src/main/java/io/datavines/common/log/ServerLogFilter.java","gmt_create":"2025-12-25T23:44:13+08:00","gmt_modified":"2025-12-26T01:12:20+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjDn+NhjKCkO0ZiUW3cN7ua4TqRpQqc0I6WY1GJOg7cxVsUX/xUhNMoxUO9YRaByxCSAk9hnhjPJlZ8pe5QRB2UrDjwqNK6m+s55x4cj9CJUSsG84V2srK8eyVtoNnGNYZYSeSR85XGnRZ3Bh0uDkyJ3bTOlnT42N3SN7kj4V5vMUI4E1BXm0oO+PzUK7MAwsoybwF4H5qJLa7XWxMPbYETXpJAaIkklufboZ8/IWqXgLqyvMr9976Vtrm1f1MSqkw6JcN4FMA8nv02lbErXsgXVDT2gWZhAzYZHyFrWPUGnq4G6BhJoOvjSy4BJcjjh/GucLo0fPr07JF5TYNxwdkB9S/lMrt7Bf3V/56mPI4HMuOB8S8gILo73DaPD50MSS63BX9XypdS569dB1JyqaACNJH4/Nptar+8gkdZ/Ot68LrpjOs8oktxQ1Juvqw1IDvySlG7TlVgSxlPEaf4OXgj6NvFL/TAJiNjR1a7jHxhsAlEAyawljv5lF8CLWE96e1iYS6QlMVQ6iA8wiZY4wuJFL3SygOk/3EuhR+kN790dnrwTE0fuZkePB2kaT/NEJogbTI5G5MQ6d2gdteeCiJfTY9yUx+tyv/Pm8BgffI814AhbGxm4aP3LnL5pD5Su7g2i382Sg6+Y66CK8fYDQU/IC4jWtS1qQfxZoaN99m/pJfCfeWDJ4LeJJHILioBGha9Af/A8Hht7uiqD8viDeUcA1NIdno27U+iOG63a9tMPHy61YO64XEScr1+d8GzenpN9mdS1F22Z5RKCKMgFH5TmRCZ1DxHqkzKzJP8vs1y1NqdrgJDueeyA8UnDrR0dTzimPDN8Efh16dHfmAdfygzMfCPzDROP0Ea1eRDphZQgUfDi5RkYfMdCUQeKD4g4mPWdO1ac01EKopJC8WaHtLoS1rKlmy5dpu14cRYbH2hyANf3snxqsOzwQBaexPh1Incc7pIidEzn6a7irYqBmYCXv7Nm0LTLYa2rBGzsw+q/KZfWKAzlewWu3JzeQhwJcmtJeajvgEbu+67DF19xTQBH+yHXAWaH5ZgpC3Je/++auqPFMm39bYZiLM79I8dxV9Tj6N4qpEssGJBFkWLvpmabrmwH1X1AiWi3HEW2L/QhDrk1+YeacrUrrRxqOYCNW3KWyZL+Z5uBm1/NZ5nCHQvB224O+r7zgndXW17qGgpC6rPkMjwVfPWvWuV6TP6IINVz+YkboPkfrLGfWwM/T7yI9zzuRjZJDzKqLksnzhozl","layer_level":2},{"id":"08bccd0c-f9f2-42df-bd89-4c3cac27a61e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据库管理","description":"database-management","prompt":"创建数据库管理文档,全面介绍DataVines的数据库管理实践。详细说明数据库初始化过程,包括如何执行datavines-mysql.sql脚本创建表结构和初始数据。阐述数据库迁移策略和版本管理方法,如何安全地进行模式变更。提供完整的备份和恢复方案,包括全量备份、增量备份策略。介绍数据库安全管理措施,如权限控制、敏感数据保护等。包含日常维护任务和监控告警配置。","parent_id":"74203214-3316-43ce-b2bb-545d7e140a7e","order":2,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/resources/application.yaml,datavines-common/src/main/java/io/datavines/common/utils/ConnectionUtils.java","gmt_create":"2025-12-25T23:44:21+08:00","gmt_modified":"2025-12-26T01:12:51+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkNZ1eeq9VaMBfiyxjFLqUB9KJS5936QlVCotmo59AXRQkdPRNBFmGoX6hlq4bGOtatSLt7VoG6vTwqd1pDhnR18zA55SB0uWqT8Q+99V53YVn/eA6w1Yih3s02sMNnmHfi88TmWj6bA/jUWIXA1YN2NKy/qsdPvkEJZ3BkrAiNJUwsPqiE3pYEEA+dB1I1zckjyaiQ5oyDXPmvGwcGEBJl0eTunAnaWzOf3WTxYCuYSylmAJyzZgG5NhMlTC75luJA/UPjTkRok/FxaGW3wjSh6mWEBTplDPSHGUsXl9f+K5WxNIZIkut69fEZ+1tVf5jvFdi7OjktjXDPtd1WEacEOQvAwDoIh6GBoAlh/symNWZSVet6fgb34kSlA/efYse1780vt8RDy2LYLDYYCt8i7hk7eNHZWm6hFwOnwVV9xxupwC8wn65mAt1iKDL8NU1NyksSFBfS2RxMK239X9kQA+I6cJ0SRMqIXtyKXYjNewh7fSBPHZ4/UHayl+o9V8Z7Qb7SCvR7nq5lezayoBQYsLem6wUHC4HLDiQbte+oarZR/1uT0S3QHwMCMbe21GroHyZkiJfIwOzU7bnI4mYH36bOSqp8IEXRF6Y7CoSGdcVnxEC6omDnrRE5EEk8SJBtPO3VL2KNcX8bW1bFvlztptX86ZA4vdNy/1qWbz0VZrTgkPWo0eC1Uo4AL2SF5IC3LNdjNIQibKueKTx16iViG7t32LlGs5owF+CWC1zgzgyhc8mrVBWwzB3RQ3yvkoCXRajGDqK5Dpes7ZNX0m7xQ5I9RSGI8jUhce12rn6ax4HMLr9BXKEKjYuBR+6/XNRubp13wgCPNQZCKmR9AwqFXLPA063zi5o8j6Ry2aGBc2TY4mtDP31VRL3Pp3s8lTzduVvrjEDT9fHPQ2ZTiIZwtP+Jwj2Gha6BRk7JeyOGfgV+RJGL5MwQOKyCYU81TaDFzA666fmlkV879cpAU53h4oA3PRWDqOmkWn+fweH6owgqhykVA1Iel6aDXk7EPXjTa4NTU1YGUAJ+3qQdfgVzIqPu7a+C0nfyn2AML3fupI2kb9wkDdhVMBRYDX3W+7Ue7nh6+sOOGm6S6aI3cICduPNOxmSeguTLPHSbx/bNxWbOQMoz49TKF0JwWdh6Z0Mhb8svOz415yq+DwJl9zy2DcxdHfU99cu8BjEdhFl4ZS4GQb00EMlsPqrvh/X+EJUOtzKMhrEH9Rl85iAvN6yUimrrxHdGcjgqyUy2JS9QyK","layer_level":2},{"id":"3280b206-4eac-4c5b-bc1e-0d8b19a3aeb6","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"飞书配置","description":"lark-configuration","prompt":"创建飞书通知配置文档,详细说明如何在DataVines中配置飞书通知渠道。包括飞书机器人Webhook URL的配置、安全验证机制、消息卡片模板的定制、富文本消息格式支持。提供飞书通知的测试流程和故障排查方法。解释LarkSlasHandlerPlugin的实现细节,以及如何通过飞书开放平台API实现高级消息交互功能。","parent_id":"8938d0ac-a871-4818-9b4d-dcba6e588233","order":2,"progress_status":"completed","dependent_files":"datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java,datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSender.java,datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/NotificationConfig.java","gmt_create":"2025-12-25T23:44:31+08:00","gmt_modified":"2025-12-26T01:13:47+08:00","raw_data":"WikiEncrypted:iMaibsmg2pDJgbDZRQwmyQZjMcMpFF0QxFuxvcNIETkuPYlcmBFVGbVMWptp6WivEIwuTq4YAamDAdFGML2OHo/nY4nAGXTpmOTXOJHYKUcRL0fm0atDalX03iEKWZQy0B3+7GCtJozG3Du2iU7UrOFOA0OHexs1NB5EYFyRj1UyvZVfpSbNrB3Vk3NEX+A3P268Ce9YC7snIBPOCVnqWT/pBGENqzbae2Yv9A854cXFNFURiA68N6iWVQZH+NDfGViYYC+2vq439xo2rSOD1MO450azHtfGhNLXxDRovYh+osPYpXsiFL3yTXDWJtyf44uIQ9pHcbrfwn58yxDjf1w9+Qa8CLsi1OOPV4hC2BNohJUjXJZVX6RSNMUeEHzOG6G5zXhJv3ll3O9ucq60oIxz3VngwbqHZLM/qI8lD4AKfXGoYRTm3HfiWiXEyu7qo7ASlBJJBUgSBlbsCHiYoah2rwkN8WIv4s4nxdnZdPKmVqmwW10U1k1SX8J04i6TY+OBOmSkMBCYNYdhbaezoor16i/NmIUZYdsFU7hB8QUmNFpuVHp3kWWmWdwxem1Na0l6BKo7BEujQ0ywUJqsh820AHEURhQHWtbNZUxgYpEwSjQO+g/WGl08Vg8QZd9rXlJWCd/eaGXysC6hB3K5ndfyTqi7Vdl/1Qka4VnlEKp136HuebmX8/1nHF+6nlmYnWR2Ku9dMadrc8MEPJ47yjhxhY7ycuH24Lz+z90YLBzzGnJZk7s3hbct7nNBr8DzfseURA9nhE8yb61yJx+yP/xEpVi7Fw++3zTD8iQmAmkimA1xk7YZA2ni/a/aSyPaAJxyjRTSCNVQTheyEUYiuLqCUWBiouQ+AoHumIiT2kxC8nnlpmHP938OEVCDRr8itCBQUMx7m9MSbu4T+MUrEj24S70qoEueBrdzKsfVPolrSpIVk6SwU3/gvD5s1MMf10U4w5KjjWF5NnxGH5oA4w21odQFPeey3aH+M/ka0gzpbOxXfwtpP1pNFuD4eBntnFA2NEtvwbB+iHjjMoYih9mVfX6es3a187HtJRqx4VqF71lOPuPRG0f9mrWYysLBlAq+m3ZK6+/Hy+JVqzYHaz3FJZx04qWp9Sx7RnEXkdede4t2VED+ruBrW3STtzG7bxzz5qDsx1UEr70Z8nFPeDiCf6CD8y7EWXNcVreQJ+p5a0xiiCQWRfZKCOQqAuP0DFrvkWI9GE7tDFe1kc5acRJNQ0tOgYS2eajCHnOdYwpEmi8+neyIlxwPoAwQkFDv9oD5nntjNKw2S+2asiiOIxPJQouYlh7MJqN8LMhBmABH3Bs957atx8wTwHrHLITijfvxixdOErM2QMfkeRkmlH+e2r0nKQCwW7W1hN36Drnbg1kC4S+mj63ltMrGT8ed","layer_level":2},{"id":"6131ffa8-42da-4114-b25f-2b0255704d52","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Flink执行配置","description":"flink-configuration","prompt":"开发Flink执行配置文档,详细说明DataVines通过Flink执行引擎的配置方法。包括Flink配置构建器(BaseFlinkConfigurationBuilder)的工作原理,Flink作业参数设置,以及Flink集群连接配置。解释FlinkEngineExecutor如何提交和管理Flink作业,涵盖Flink版本兼容性、并行度设置、Checkpoint配置、StateBackend配置等。提供Flink执行模式的性能调优建议和常见问题解决方案。","parent_id":"69630b5e-3d0e-49f6-884e-8e9fe153a0ff","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-flink-config/src/main/java/io/datavines/engine/flink/config/BaseFlinkConfigurationBuilder.java,datavines-engine/datavines-engine-flink-config/src/main/java/io/datavines/engine/flink/config/FlinkSingleTableConfigurationBuilder.java,datavines-engine/datavines-engine-flink-executor/src/main/java/io/datavines/engine/flink/executor/FlinkEngineExecutor.java","gmt_create":"2025-12-25T23:44:33+08:00","gmt_modified":"2025-12-26T01:14:58+08:00","raw_data":"WikiEncrypted:5ObXku8AzOSDfLk4OSAc/u9RVwRdmnK8jlYN/+srjllqG6c/QIp/RhE3Us+xxD5Dom3kbG/XLxKJhvgEHZ18mYf6zzM0FUbxoIIvgTBOYUlVzb49dh28RC27GrCxhL1aZBQHs+ghF46ShrKTSvccZjw5lf60g3iSAu1RO/22nlLy+pszoSvPuY+Vcz4HlAEbFefsMFfuaivi6oq5qOVFVqdMGiu7Iu0woh95VobgiAXFp6HPTjZlowk8MeV73woZO0HuueVK6J5Bzvplc15UeKTpmYvG3RkhsMF6qSntth+9IPiwROVw/5oyQHhruu1nZRXXndqM3B1n4RGWz31muWyjz/F+fpZ6qHmy83JTJJ9+EAZhX57/xHzYOCiL2GPvd+5qhyJFHb1RC1krTKPsdgXWEwNP27BsPUMah5wwRwjrqG4L81vcApCG7GMPtW3W9fGRi7xOi5ZCJKsLA01d7LnTCmy89F4jsXJsvA6uxc3/qPKdXjAFz0nFd2N29bv8o3ETEW9OTu8CN2I0u56ymg7CqxaZZwPNxGxA1eUDa+fd7+jSZ9JTEv1B7ztHL9dGyjgOyYYSceKdJcZVBtRaE4c8aRamyhpTbBPaULCAQ+YrDyEWQtaq4Lfw9UBMJWVrlM1IZsXjHoVvv/WgbH75HH41ZDLmluxASknWujZY3Ht+MGwb7UGARXR02WirOmgCip09VxbJXoVa/syprG2rea7urOy/vt08hofYDwL/66xbdM5fYvKsfXAQqhPGKIERRSIZ+VX/PPP3VCPalX43pxspDhCYJJSs+Wvz8H/L4Wj7/0tRn2ZRYzthh6MhUJNnjHH/p1YviHW37jW4/iKXntzLnupx4s1CWb+tW7ZDtbiZyfcFNjsdNPsh0OzQQoVDkWEHKP6+kvsE0BpwlEvEMZAPw5PG7q006l+sQ7+dks5WO13Ycin+GUUFmO+SozReSRva0zrugL1rNe5JKADQhgP2iuPVAr8p6ZsXo1BJtA945ESEF02Jiab/P1WUYCSmEPLidsMuiWKgqgJdR73EbfycRqflJRD6kp/Wu8JD20H54L+tFrqOsbric5J6dyCMrs/TA7Z/3lPjitguQe7u1gALz4hFqlchw18ERzKHyMH5+DxvyjnBmtC6kFQvGuyBrOB807fjgiIt6J20i0hNc1NpLcLsrvgLYgnMbq2ULa9DdvM2nBpIO0BNPmIGEZplrusIsA95vfqGfKELJiKTvOKFilnAKnSVWWB7TPIlDsnBHObePIrrqCFYcpmb+OPAW7oz9qsPgl7+t4msAXc4+h1l1WMnIGyaHjW7PzY0ytsaEoO6ViyL6UyZ7w9GmTYPgmwuVrJKqfeKxQ42h3mTxMp0TJ9CuEziG/hBlflrQSfNVVbtqcEL0zjwb+rdYVMuHlwER0BgNDtuJeDd7TTBN2wRWtBqDD1RCYnHqfnkaJw=","layer_level":2},{"id":"1e6b21d3-ffbf-4413-b2b1-7835661a6c7a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"文件系统配置","description":"file-system-configuration","prompt":"创建文件系统连接器配置文档,详细说明本地文件系统、HDFS、S3等文件存储系统的配置方法。包括文件路径格式、认证方式(如AWS凭证、Hadoop配置)、文件格式支持(CSV、JSON、Parquet等)、压缩格式等。解释如何配置文件监控、增量读取等高级特性。提供性能调优建议,如批量读取、缓存策略、并发控制等。说明如何测试文件系统连接器的连通性和性能。","parent_id":"3268b632-dada-4561-a9f6-4ae317e64f29","order":2,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-file/src/main/java/io/datavines/connector/plugin/FileConnector.java,datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveDataSourceClient.java","gmt_create":"2025-12-25T23:44:33+08:00","gmt_modified":"2025-12-26T01:14:08+08:00","raw_data":"WikiEncrypted:l1O7XWjgWHyLZEgkeZtuwTesAjwFt50HoiDWhMuPBR/hq73qTFjoV3dwAzHlNhB3P/bDEVyYDf/W4YQPmXywZXrgBh7Qfa5VCzdUlyv6nFK/HDBZGBNU83tpPnC4gkD9qf0ukWaUw5w91E/G9GN76yOX+vnUaArfO1MvU1lsncRsLcpKHkho69f78HqaQ810Zv+2j5oRuoBjc/byIePxW0OrG3C4cHcJ+QgrAH9t6j4eFQac0hGYnoMUlNf+/Jmok1EFmC8DilF485iyuWK+Ab2qFZq8K/HdfX3YBLHJ1DrDW9YYqXwDGmms86mMwWRV9KyNac/lNAS8XjrzMoRouM5EDnPG3YfG/2EKXCd1AyWNq98YCKJE8P0AP5g7VfgxNv7LmQiaA1UfTwqQMxwfgjf4qE+1Zykph6xk7WQwoVQ1Y+dEEa1HNq3EmaOG7AdPOKW9oicelX7bRhP9TEDS/SocFNjSlKAv+VRz9zOeI9UN+W7ls9XZ1SCX7hOBn3hfkYnA/TpNJ4sD/UVym82vp+EIazOoGS8kN920yCBWWN45p9QsIlgVYKC2YXgBRWLmgpjmR41a78BEPVS57WAu/qcI5rzfKK12kAvAyVb85Ijz3qnM0d0OyzX2uEv0Aelzc54zqgGn79CE9htkzt1n1K7nZQV9jT1SD9YSBdr1wlhnDajU4TvnOoUfljZQ60dppqnxRyq1x3MM1QRRcmDKHQbbKJ3eYNlX/cfEYtAmYVBfIQj+xU/1xdx5smH/Wo+hfIjDvlgfjbWxZ2h2kjDPXPOB5GCx/X7wIaRzpKiEHcSbDOPAKZOWRJk5xJdb3hazOZajwohherOeu7RKF05z0tiWdkj6Kx44rbm2Bx8F1EQF6faLLWNAo1KSyHt/EmUYJcd/raTgE5/7PEcN4UIYFu4i4chfrFFXWE8KtsZa7phW5ZrGjE/tew0BrKTotxDr7XI1euakQofGrtTVT+lwtHweKisytCpQlZNn+41K1DfTI0Qap6jn29VvpIDuJdqt+yObvH4X9EWRP0Tc4TP9yXkSDapLJWu0AfgIawOAg4Fya2P1ob/MCg5Og5aTteGQuY/0JNf50Ub25Ryk9Sah62T8WnfhdlRevPVattryqOkwGiuNl4Er42nmXbcbrA+lsdHOXUW3Z3XyTaQE60+b88gBgT4Zx7eFjVWSZlSkvt1MeJ60kcvzdy/LISeFGZQ+pn/e4YjQQPJUvLHFwe3OrZG0gKYI7UDeE9tW/zLW7MhndNoGNlBkYLVl7p640ajYZwOsUxMRnWGrvaGu0V4p1g==","layer_level":2},{"id":"6f1fa09a-2cd2-4016-8fe9-896c74cea65f","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据安全配置","description":"data-security-configuration","prompt":"创建数据安全配置文档,详细说明DataVines的数据保护机制。包括敏感数据加密(CryptionUtils)、密码存储策略、日志中的敏感信息过滤。解释CryptionUtils的加密算法和密钥管理,PasswordFilterUtils的密码验证规则,以及SensitiveDataConverter的日志脱敏机制。提供配置示例展示如何设置加密强度、密码复杂度要求和敏感字段过滤规则。包含数据泄露防护建议、加密性能考量和密钥轮换策略。","parent_id":"67c4da86-576b-4264-b187-42216255a143","order":2,"progress_status":"completed","dependent_files":"datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java,datavines-common/src/main/java/io/datavines/common/utils/PasswordFilterUtils.java,datavines-common/src/main/java/io/datavines/common/log/SensitiveDataConverter.java,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:44:42+08:00","gmt_modified":"2025-12-26T01:15:17+08:00","raw_data":"WikiEncrypted:yP6vl3GzzNMVOI7+ToNUFfZIdak0Qj7AaHmOdke16XWCVxXKHlj+QkjeUOf9abJoMfmMUFZRJBqkFvDIXoOdB5D/Z2l0C/R4qJlIdfUISCyZ40K1ernyHlxkKCnEFk/Mbb5M6cDLBE3pyvEkdwFQ10gPVPow0rA9XcIWYgelHjMd0EStt/iE/l86Ifu09eyuWXwpWzsRPwalJlXMG6uhnkeIDN8xE+nYm9w18oezTXrwvnxuaXdoIn26rmZR6Fl6qiX5mZGjmgI2gOSS0UCupRbFFI5v4p6JMGo7UbmGnj3Vbx7JF1sO3PrC8r2AX6OLjGcKFpKOZWjCVxE0oQ5XKPG93QcHuScNO4iXJi1qE6B0nKz0bwfgINYo13LiR8kJDaWa1JxRrVSuUtCJH/5vhxzFwr3IBU4gMaXSrDq2SsJ10wuM5PzLKCBWd3kci+wF2yoatKaZ3YmlE7EXctbFYNwWJWJhIUY9LmHcQ+OpMoC6+vA595xglEXF4Ws4cIbqEtQQLyBmwrmvhzpDuC4Kq83QGvHiw7slY/6tp3WuzgZ7nhBLVCzA2+ktiqUCxX5b6xEP36XHilXWYhIcIpeSAAlK0hw/RBrY4fh6VV1ZQgl891ATCpkrB63Th+YA09lV6kMqKObSyBRJbHv/9kt5UpWuyd3JLFZdkYt9pUWeVesqH0tyJ5SiJdEinTQ9BqnjpoGjhm4aFTM8IGX06DwGIImB5HGSIjq6UtGpeALxms6qfygDvGREE1TANKOs5wHtWI4NIcdXY3TK5Dx5WriG2VZAOiMw23LG2hmJtwUqJw3NXVAWNK0cU0LtfeDVLMiIeCGsVcjtszoz2LkUWlvr7BiLWD48Nf/5SAIFxZv6NAKyMVRrkzvN66jmQGQkZLX8cbZvNsNUk9+NtSA7GoqD4AgAzmImN8Fw0AUnnHUe/bw6xVkORfwxGUCxtTTUXVxTOqS55m8/KW1GQK/Pzqx8sYEemE6qfQ4fHLxcmUGrqmUNmdCaQhhBkglng5H2lgFz8FeN8dMh0o1EYYcUeUo3CQ/H6u5HYY9OAfewqM3eyyCwX48HxBqWJkp3ne5oUbn+Sz/z5e6ny+ncdqEeMTKFzGw1IKOPRdP2lNqKn4QilzIk8+o0Fk0v4maz7GuyFgygV4aXZTc9znID0WUpNBtyZfsdaD4OlJTJUxJEp8rzu98mUufWy6txKyU/thS1NnAV++bTLktxvNZ/QRnMJKgfcywvGk4Dqe4YKosERb2hUYlo7rbkZU6pjVPMcJpNP9sascUmhigkwmsxfBmwvzrI1nVf4cL926YBjHWA3jw+Rv4Cw68Z6U8cHcl7CIwJ1zWrmb7RsbN9metQ0SyNWiJifg0TxUYeewOARUxyBB79eGI=","layer_level":2},{"id":"b5950a58-eaa5-4a3a-abe1-aafda3088310","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"分析场景","description":"analysis-scenarios","prompt":"创建分析场景文档,描述数据画像在实际业务中的应用案例。说明如何通过时间维度分析数据质量趋势,识别潜在的数据问题。解释多环境对比分析功能,支持开发、测试、生产环境间的数据特征比较。描述异常检测机制,如何基于历史数据自动识别异常值。涵盖数据治理场景,如数据标准符合性检查和数据资产价值评估。提供具体案例,展示如何利用可视化分析发现数据漂移和数据衰减问题。","parent_id":"d9c6c09f-4495-4230-aff6-8582fcde95a6","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogEntityProfileServiceImpl.java,datavines-ui/src/view/Main/HomeDetail/Dashboard/index.tsx","gmt_create":"2025-12-25T23:44:45+08:00","gmt_modified":"2025-12-26T02:08:42+08:00","raw_data":"WikiEncrypted:tQBPcXM7MY1NSrvR+X2SQLsrQstHi1S1ch1erzAwOT0mnQTb9T0uxR4V+CNUlYue+5bFj2L184HWfgOAgYGpqx1CesTDlx3Le2mZys3GBBg2b/La9FkcsALoik2C2/SMuAT2e3RWJ5Qj30ub+YYTQamXqtMuN76tAN/3TBNjnooLyDKSBRG+wffpT3/E7fMGCW2zTNa841ygNqtdO62suQEzDGmf/Pfd3jkwIF+avBsplCfFFTsx2azZQG0zptr687nvch6Uy6vNOwiwkWVimwu7X3J3+N1m+pZjotpmUFTG2hsoM4Q11vkrcqOcwo5FyrvVjnnCxW4Ey9gA5VQ0uP4OVNYh8IEnEjx5nnzYSzby0LR5RfWQvW+3hu2Pg0b4TitWw0ZBlwkrZwOVBQcC7LGL6BZ7lz3xSOrRNTYpXvmIw2+3CR0AiV7aNgrPiUqFxWQ+dVGl3GtULmc2uattTRZTKf4BjZHod18UjfaQmFdgxMjgaPhIwgWXVhtaLjuDPgBgY/uGIzTasaI5TOlhyigF77mOL+BC+pjREx6OJ4a9qVjritkSYah1kC6QYTMdHKRhUXke7382JyUL1xscE9yzxpnLTE/m2x3PFlB3dhofuA1WSLsZ/eLGhCvswi6dD+Ew54sxml6/5SRdp0NlGusk/+Y+tzc06f8lmOgwbrTd3eSAFaKX9bAMniWEND3y7VO3rAiC7jqtDdYj/X3i+T4aVbwD3gwiKONHWoOP1Emx10MlDTFZszvp5KMHlD0HnA3TBeAE66NCtvEuzyMFbj1s98WH2tL4S7BlZxMrTMio9X2AqDtZh73mywui5eTv2hgRfim9CSsfQ+xyYOKGesmP0TDoSbeiEVnP5d1+Y3e7Hix+zR1x/jEQBU9OkdRSyE+JJK6ogxBNqWS1DKoRR033wkibu+f+ulgP5Xevg4A5UrzdhKdrxTMQDRtLq5ysle+eohIJQMwwIhYgmptHRmgEel7hMJH5ayqgXsYTFcmrtNYhuOdrWmP011U0At4zwVumVFEywKw1ojGUYH1t6ckJSQzBUdPo+EBMqWlkP63AjZdp8+n6c8shoAA0knhsxiROAi8rMLSQXZu3UkZntj98/hUjHbniZSHNFVdWJiNVSXNkNgH+ZWgC5ilQ23Z8xBVL8QshdGAlnBV5oOh20rp3dl5UJKaM1nC8kFobnHnvQbyWs3OclrQcNUQPB0WlABO1PWk5TBS1sBKS0EDy4hvswIqPYyXfTgfIC8uYN+E7PGIRqG+uXiHLW0+A+P1d","layer_level":3},{"id":"3614ee98-0803-4f0e-9a53-acbdb7f2438d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行引擎配置","description":"data-profiling-engine-configuration","prompt":"开发不同执行引擎的数据画像配置文档,详细说明Spark、Flink和Local三种执行引擎的特定配置要求。针对每种引擎,解释其配置文件的结构差异、特有的配置参数和优化选项。提供每种引擎的资源配置建议,包括内存、CPU、并行度等设置。说明不同引擎在处理大规模数据时的性能特点和适用场景。提供针对每种引擎的最佳实践,如Spark的分区策略、Flink的状态管理、Local模式的资源限制等。涵盖引擎特定的错误处理和调试技巧。","parent_id":"d3911c90-857b-4391-880e-b23a3893ee7a","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-spark/datavines-engine-spark-config/src/main/java/io/datavines/engine/spark/config/SparkSingleTableMetricBuilder.java,datavines-engine/datavines-engine-flink/datavines-engine-flink-config/src/main/java/io/datavines/engine/flink/config/FlinkSingleTableConfigurationBuilder.java,datavines-engine/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/BaseLocalConfigurationBuilder.java","gmt_create":"2025-12-25T23:44:48+08:00","gmt_modified":"2025-12-26T02:09:34+08:00","raw_data":"WikiEncrypted:YZI97ep9QXDPfRNDXs4+JN8fItX6izOdiBYfWh50ZviKeYFK1wa8uh0NG9jytBa0G25/gMvjKonji2S+nXXDEf0GiIUCtKTOZUa6xAJZ3u0kFHWigDEiXjM8ym2Uu0paOaxeQQvvDxlZe8BZ1qBcrhs6XbclynXL7ldqxLlR3rUMs7RhdczhrH/xel0n3kp9qDLsx1d9xly5wKplDmnn5xkngkw2sb+/opecmz+qSrqFIdlkXzefEPQtmAfqTgpT3KLU4HX77LASvlIha8FA9tqsGPeD8wIQTiHnyCIxKW73gDv2feygprwSq1cp8gOt0SpVgJU9S84jZUr8EN4YXbJQzfW5HOHcOyXbv3hlOuqyp+FfG0ZDJp9DLPXGAPQ2YcM+pdqrTpZxO86r2nLJftHRDo0WLApOl63WBe8+PWcvGYEpkCm0SfQyI7HNV76/dOMVrUc4vsVeoZC3crHTrksr0FeqdaoFYlcFdVrdL+QWZSf8aAAexclPS4dQHipE5cpk+LEqywXBQk4aGzJOTCnO+wqp83F993eteOCTJINO1KKJFRqfZN6zWLp8gvPysTWMgF4T3L8SmuLeeFmLqT/wnQvLWnga0gTz3YXlkbzciacIWH9rgGXdi+WhdqkliVuLYAbHQSiQ0MHnl1wCNjCmm1zXXWNdHZeLiN9xZpnmy7udyGLyR6TS9ol5VRR9eqCc6E50xCRTyDrCH+JMpvSx5Y7PizZfJnr3e52LgubeBzlg3do6r/GLf6qRm/BkvY3SVoiOS2OVNv8cnbmAJHexiQentIzKrI4fSz7SvrPrQScAbiulCfClcqN6i1ycZwmzk5rxF7wiaajSXxLhxp9xo13e/TwsooFja/VBvzUwFHyTps8TpbPipg/209TUFrcI9Wp1AubguQB8efx6T3fD6LlzWMKH1C9jfgTAQ6kpEjHbvhxgC+yXP6m4lVH383n9crvVmdTdf6RVguIQUkAQUTUt5IZBjBRLq08ano2loxFOInin/3WxCI72ab2bndoHgZRCUzTxiiFG9WnFEUS7v0V5evvjcwIViAwIuPeY142w14WCixz5IupFCrnyR1Huxn1Ta8EoohqQ2VEm5QaZWrItzWzl7pJXLQbepPgDEm6MYrfw+boFlSDkf3FlvM/kuUPt4ZCurzxWsub1jyZwtrIqAIZ5S1D5FqHWlpXmGU19BqqiaKtVPgz4HyGFbrmPZIL3wsKZrNWjUvvqDjeozq9RufVrDedwaMTRrwueQUHHJ+oyyo3rMc1UpcrC9YjrMqEit0Ul6GabDZYi4fK3NhMqkmfD1WlFkkRm1r252Ya3Nja8tinatUB9chFnQHNd7G+lkm64DdIXq3piL2UEvpNSZvN9C+y9mIIWCyFNPuOIw+rv7kcgZ00fINw6ODGws21DK1K9lmBJz2eZJullWPAK7/mzxHZ5nIUNaoEuskJ9H+UHVm06suxwyGF8V/MwLW+04okyN3cT6J0H5J6rMy4PsBtMk2mUDJaBIXgRQHDVp+NNp4eBNeO26TMO8O/ntqMHmiUQwwAsGSpM793tE1aMyjenAUr+3IvzEKRtmT/22R5gwP1OdbfMjaPkw7WyjzRnIMRRoICnHVuS6yQwntCAwGC9gep9OP5G68qrXC8fj407uRvFtC2s0B0K8oD4r1fdA+LxPQMZUxftRDHCCfAVKoe2se6Sm66/U2kPdUJKZdPBDriTj6iJXq+ioJSzWBdqr6+lGd/6Zcpay6R1B982zYsDXykLRtMn3dErApaRLCn7VlcaZLTTS55G","layer_level":3},{"id":"7fb0680a-a75a-4a34-bb64-b3eef58c4117","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Connector组件","description":"connector-component","prompt":"深入剖析DataVines Connector组件的插件化设计与数据源连接机制。详细阐述Connector接口的职责和核心方法,如何通过JdbcConnector实现JDBC通用连接逻辑。重点分析MySQL、PostgreSQL等具体数据源插件的实现方式,包括连接参数配置、SQL执行和结果集处理。解释插件发现机制(SPI)如何动态加载20+种数据源支持。结合代码示例说明如何扩展新的数据源连接器。讨论连接池管理、SQL注入防护和跨数据库方言兼容性等关键技术问题。","parent_id":"5a95842d-bb17-4f7e-b3f1-fa2cbb84163e","order":2,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java,datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java,datavines-connector/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java,datavines-connector/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java","gmt_create":"2025-12-25T23:44:58+08:00","gmt_modified":"2025-12-26T02:10:51+08:00","raw_data":"WikiEncrypted:k1fKnz3ioW1yTq9x1Tu5AF1I3uPS3xiRu0YO3XMqqvrMwhm9yss2ThXXbzXYMjB4jaBs/v7rChBU0+MPxRNe+lSgWUXIZS99xL8/D2wKytFcszW5W/yg82dTMI3DxWY+k/35HRAvIKnPQe5maQ5w3iqhCcAcEiINqgQidV3bBSBmORHKRBgyvZJ8r/vPnBZBlZq/Aj46WL/Fej/rkzpZR7OrnUlC8FvFSf8uepzmNf0amHT8xaGoei+6r4r4/vr86e+rdJH1Tkxc6+u1Td103q8q9FYGKx724dWKHLPTMpSsO5yjTpzXQQbOs2hlKWCjU4LZ2ddgXCnB4EQOua52nt/mZpMTx4rtpASZKz0s7iC6IFuZIaGqxOnMnj0xuSkJGtW/D9Ttpxa3jgK2Ky2Ea92lbWSgS8mlCRB2qoZ2Rp/uJZlXWxoo6ebH8/pD9xI2fJP5+dvn92fpHPMVRRJwGKDMVu/9XhObNwJA68yqNCFjskHkuwCOe4vjjY0Y3ABdyARsgvRxakxkELCZYdBQ61Aw+qWnXVDsbppcvLyjT5dxr4kahKBXpUNjSFEU1Z3BX+WMznpq2BRu9VMaLTrVfuYO1OT8jOGPpKUyZ9eFcY1wB49Q3ToYDY+Dpt3bpJgoLfhIXHyrLxKno+z0ASqGtz+pfb6G55uTEYOfC77m/d2NJk24hOwT2TpnvIVzHrN1Qnzdu7EpKYI1j8RPLqYMV1HqZrqJ3j2CCs8SLJiDFnmB0AK1ch2XeTl3370aoMeLjBt/dVjZxWm8ndRwTfwMXEpnSgPouq0TaxQ4G6h7jlJDM6Mel431KJ9KRmrdLwLnzi9X5MD1MblQByGis9N6I0pZBHevENhDb+1DfPfugE9q8pCUN+Ay2s3/R+vcJ0OquU2wV8lRFDmniGUmu3Il+U9U1OjI0nOqMqhR8GHQEbhjeLJFktbbyuns70+M/sJn+u1/ULykbBkQ0IVRnNerOi3Bh+p26jKJNQnNRvVOF61QT0IMU/iFb++GRIQRET4XgAqNzoP8dThbvsoCebiAKksiWdZNrjbfLSaWU0q4xVlvLYjqOELx9uXKXP51ciofCmfHMjkUaJD1vX281PaVdAfKyRSSXcM1CHAv8qZYF7ZFAXCNFQI62JYuf8t/n10ta6lyFNOnCu3hBjPb++9ZOmKKMe7LlSxkNmm1NRmrBBQJ2Ru7ZWEfsOMz06/VO9Fnd76XkzbAIgplKsbJilkmPYTni7SUseqkyeEvFqmv+u8QzjAiLoEtf6X+4feyDK6Rnrdyo/zDQfgvqgEmmVYG9PUhtiXaXudcAnGtF/ExdB5iCcJeA3AcBw9E7cmokrTJvZBNgWbEJaU1DVeeqMCsaiHY84MpIVqi2sk7V/xwPMmbDX7lOs4yVvZb4nHhiT8jsUE8C6sunDr97+Na8PSvf3ta09SLhaD5rVkxscY4JSZGyQbRAPgQ9mh7ppoAJ/NiFidV/ZGnUYZF4KXC2ahLs3NueJ0uJQ1nsBOBVWOGH/hL3Gk4evLN+4OUeEHIryD16rXXMP7RDWZkBovuFTpfb37TQXkxVXsNWJnrUxOZnwZn8wyDVA8LSfhBoWygo1eJ1IuhvcUp2XcXda/1PEmvR/fdyyUguu9p1zi6LbOiCxf2odMyRJPJB+mWSbEZzcpe9MsKQtH3++qKh8Py2MxwhVaUw/WDMEj+BIyA0ht0xO9gnqngpQXA24C4c/O/vxz3","layer_level":3},{"id":"b282f234-c03a-42ab-a5ba-d212befebae0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"状态同步机制","description":"state-synchronization","prompt":"全面阐述DataVines的分布式状态同步机制。描述Server端JobExecuteManager如何维护任务执行上下文,Engine执行器如何通过回调接口将任务状态(提交中、运行中、成功、失败)实时推送回Server,以及Command命令的确认应答机制。重点分析JobExecuteResponseCommand的消息结构设计,包括执行日志流式传输、进度百分比更新和最终结果持久化等环节。通过LivyTaskSubmitHelper的实现,说明与外部计算框架集成时的状态监听和异常传播机制。","parent_id":"42102899-382d-4ae9-98ea-ab19ba59b352","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java,datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/helper/LivyTaskSubmitHelper.java","gmt_create":"2025-12-25T23:45:00+08:00","gmt_modified":"2025-12-26T02:10:41+08:00","raw_data":"WikiEncrypted:29DQGcj0Xkj5ar8OataJBOvaI3a5+Ax4fY8uwBjIKqODn51KuZI7LJLQuyYFI+FW+riSZln/+vNTZ8pp5EqejQh8sdPGYulSPPp6Wnme3GkMvFnXb4CcVnQqbxuvmEG7P34vlorGuS8pCUCLE2u/IYoLGyCiKaYGQrrNyINxm4KbRXvqM558CnGxaQ86O3cHN5FJS4s6wvtTP2DkoiKIhc7QtibvfgPqH7ZRd2BYVWfi+jpcxE1Nes2EiEgWz5mnsIxVyek4D78Mo4DDzDXelF67MKEz+YlwRbxwMuXH6aL3BgoXyAzp7cLgUKcLMoKjlXl29yYY8I5Z8aHnUtKAxl/aOHQJKKwLyM/en71w1lscMi95tW9xLjveNlfdAdEOJfh3MgCpiLcMsPNfq8wrJVREF4ew5uQvejllHiOgme7+5rJr92F45jiDAqPer8UQeUvde8Y4Jz1ZooW8Jkw7ar/eCIzjRgYh/lIcnFjuUDb1UWkU3+FoMzERV/OWI+K3T+MUBxJAbexlL1FuF8C/zlC8VH+Kk87H3dBpcFgDCFTndwOQCH3SLWyNWsSmY39DKkslS7oSYSnrC8uEDrItUmdUO4N7djQx9pTkmWqJTk3W5j5VcEA4Op0LcgTxAIsQZ6mUXt+6dx7HY6YO8jOpGhGpOT5UmtswagRN00QxAOQSyQnG6Zzsj+bPT//r+aEWBpG4s7vDryu7fTzgySZw2Pumwt8BjlCdHXxCTY3JLzBeFfPa+uf4ElrPFjfkIxI7o9FDoZqK2FQpL+TK4ACjjhEN3GcvQVtLb1J3vY2ag6Vp6qQe78WHBEwqCCfxBPy/X6QgJmKLV++OfgSSOjZPP93H1kcCmf2rFC6Y7lYAACX4qxohgxZTUduzDVTBjBU7f3x14oKsEHmwGlrENq7y5M2nhSGgxWjMFnIDa69b0RFBB0kxZ6SPZ2dnIBwaZZ1LNDZHu2/r4B3UI6u+RWI33k8199eT27WoIsvyYeApLH+zOFXUO958bxdcTRU1t6L9TCTBmfu+1WPqTRWadajNDDzOgsqaBuPAjLH2F4lhh0cQCW29i/JtDmDh1JmLldVTyQsEXyuwqGmWRbYWGUh7wxTd67Gxz6zh4yStVdxgAZo5a23G+wUGap9GnoSzJ3TGttESUbgiUXt36Wpx3vJcULAHyEOMAH1MooZaDfc48Ts7ef7haHdOUJhY1My0p1PLePLJMW696CxUt2ZXvjDxtD5e6VZXCNd8+sQKloZ3w3wbOcNfC0Wl+zx3IH33tpJwCaAX+lsbIvjf5hy0fixob1zGahawzqNoBufEz40RrIrjCGLcfGZ5kETsHtPsG+ruBrg4nn6s3qVHdYv8H9Ir1cJEOmleQaB9ITaa1J0fXp7YOSp+nVgnBukOae10NhWg7793iaTnR2pVsK7/o9/ER95vEXWLPhv+2Kk4NFg7l6jcpyhWBGov4ihq6m8GGO8qjZlazT8msF5zRak5kB3NAfCdelhTMG6giXxcRZxjfFE=","layer_level":3},{"id":"e3ca53ad-7c0f-45b2-b03a-0e9392040c5a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"定时任务调度器初始化","description":"quartz-scheduler-initialization","prompt":"全面解析Quartz定时任务调度器在DataVines中的初始化过程。描述QuartzExecutors如何创建调度器实例并加载任务配置,包括线程池配置、任务存储策略和触发器设置。分析ScheduleJobInfo数据结构如何定义定时任务的元信息,如cron表达式、任务类型和执行参数。说明JobScheduler如何将数据质量检查任务注册到Quartz调度器,并处理任务的增删改查操作。解释Cron表达式解析和验证机制,以及任务执行失败时的重试策略。提供调度器初始化流程图,帮助开发者理解任务调度的核心机制。","parent_id":"4fe521c8-eabe-4899-aa88-38fcb7db2d6f","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/cron/CronUtils.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java","gmt_create":"2025-12-25T23:45:04+08:00","gmt_modified":"2025-12-26T02:10:48+08:00","raw_data":"WikiEncrypted:Pkfwn5XOIad2zhpXX0eFFFaEhszL2Zzg4I9v08MQltYQUfwGnT2UZ5dROIi4rjug8cRBu6d504O7bZKx0dA5G0neXoD6RIDJGT4TjcJ9mfp4YHyDEyOzuuF03e5VKEi+S2MzW92X2s+ekbv9iAhpJJuockYDFbPL4hEPBgr8rmLIjExQbWXjVF+4jJIwgWeU3ZpRhmPwZ4PlQjEv2Q3ZUVfq5vRgMc0KEcrYK56jra0f80ulWXh9BjJfgN1NMVqY2cL+vP0o3BH1P13Ovfv8QZAd2wnY0AHyHreg8j8QIhBB5D8WlAu+3GgMbeMGZdwAQwzPouBACPk7/lJ7zvS7Q7gS839EsRG0/G5n2Y0+WkTUB1SrsT8vfT5PQohWsTzvvjGUedeIT71NXtLAzIR39eXs+FanLYJFm645WEfssVrjGysEC/u49dhM1pjgOEJugEQl+lgZkBZZTVCc5TsrChs5vhR8AklPwjbVxUvxJyH5mlo8zAWPxO22QXYi8NJhmOtiWBFC6oFkQ48FzYjSatEMHP6WUu3a8dalf3/W4E4AlXvV9hgRtcAmcpcRbD24VfJYApOmzwPmiMKVvGudsLid9vlVdvZXvjpH7/v3pIBl5IfeYE9H4p6eoyxUR11So12Me5eAA0cMU1hrOQnQjncbcIP+Yh5RXd8e+WYzneYFUABCONzOB/3a8A7QgTHN6GpIZSXDFVcwjBy3UDjrBQJDi2FmAdoDRFkP2lz+PH8HtJ+tkpuzXnBIfT8qg70Vfvy9EvnegYxa8+h6TQCZJjUhT6xprE0U4bKwEHmnk+jo0FT/9DeKgqXYYoBk5K/BSzKQsmKA4nMp5pHfjjW5JEH48SveKfIP1NplVeNP2TIh/vP4UEA4WK4tM30woPuq7II302IVMADeNMOVWK4Q184lqvFkZPly5pHZsxWICDd4q7mmhIXcfQIXDOXUtAknbcwPH/XT5W+4hGbVN12IqjPme74gyc/9fHlpOSxokYAMhPBLVzjZjv5E+Xs5b9oVO8ltl0X24mkazACmVoKranWXooXV9X6Cgjcu3oKQM+D/+grXOdk94JKCYVpnmjM+EzfBL1L/d5VGCY24HfZZaTOfAn4v2sYZCUqXYndgwqrN27ATMDcKhAosjvndIf7tmJLfqFoEJnjqjyIdXhXzHfUVx0V0FygSGBapq0C3aCkDOOFAoxLPrwltH4i4WuNZkxsH/ePWVPTfu0AFtzHhG57rE5x3zf1iUX1wEokTlSl/vnzrLPurD+qcaYXc8K8BeaPzYo7nVpP4bPN1pQ91WRvt/gn2+QlhBImUa7yGj27AHwHP2ex1VcZDtsK+hHH4A8b3d5z3JH7DuXz9yFjq15oCNJ8/iHCVfMMLYx6cTBQaip8W3PKbaX7mWJbZrhjekjqWry8nkoNFybcEuTOPcUdVVPZkjJpqT7POl8QFnWrHL8kJTnS9T97SchIByCTlBKJnTL7ct3q/4Q27nBvYbbk1yDXlZTsJsSYmau00BDBhrqLV++Aho1x/jNPOrXQ+07+F529xxwhPX8EG387ndgTzwq/vf+EvZJmBuCA/hgc7rKX5mD1GGQSC6NRTp4sU524gF6n1KBZM8M36TlmGoQ==","layer_level":3},{"id":"ddcf75a3-a063-4182-965d-304375d80bb8","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"自定义SQL检查","description":"custom-sql-checks","prompt":"开发自定义SQL检查规则文档,详细描述如何通过自定义聚合SQL实现复杂业务规则验证。说明CustomAggregateSql规则的实现机制,如何通过SqlMetric接口执行用户提供的SQL语句并验证结果。提供具体的配置参数说明,包括SQL语句编写规范、参数占位符使用、结果提取规则等。展示多个实际应用案例,如验证每日订单总额是否在合理范围、检查用户活跃度指标是否异常、验证库存周转率是否符合预期等。介绍SQL注入防护机制和执行安全控制。提供性能优化建议,如如何编写高效的聚合查询、如何避免全表扫描、如何利用索引等。说明自定义SQL检查与其他内置规则的组合使用方式。","parent_id":"9b5eff2c-3130-4124-8dac-52560ca652a4","order":2,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java","gmt_create":"2025-12-25T23:45:13+08:00","gmt_modified":"2025-12-26T02:12:30+08:00","raw_data":"WikiEncrypted:VrTOMK0P24YINQ3w81Yokdd4o2+YnOpWsl/jyC+yvNYKrkRNjoZWHYAyo6t4QMFq55WZrqJRSVtkvRUp2OT/OMbq9YOqZQe9yRlSvOtsL3s5dqhYpKRujPLGtWL6/H4BvJKaVRZQxvIQxKe/zkp7T825CawKAj04Q9kWJ0/dLfAXAV/n8CKHkFLoPYwFoudIW1myhY3ZSSgA3gNusr1McMxKFlFvnjnwlmNjMnbtb/4mPixkNsSnBL5MaC7eJCS5mSCBdS8rwX25HQSIw9JqcVAfWxKCt42/z3hbbQApOE5/ShkPuqOLPr7AZes73H/jvrWWhfv0+rXJudI7mq0em6cGNMPjwg95wOeHa1kpIppNtNfwYFWvpgQ6uotNKAhAKIHhAsRmbVk2yDT5WNdHW8TFhpi+KVLXyjwuhOQ9KfRobw9Vo9ei4vhCk7B8fmSAtK8UxGr2TUsIBscDB6LPioR4NYi02LeP3vAQJVmZsSQ0phTuOrkuNiKYjsF003HSaGiSUD1txLOy2prR+AfVLs15VmtbbllCAS2qyawwAUr2m+I9RVwfrfyqgKxcvwCXWYhftAOJx+Q/FdHe1e5YzDH+Gk4JVX4rfzNC6RgSXvLhumoesUzChiVP9YwxL8FFAK8ja+T5uZXLjQlz9hXfbfjNNaKU685LGyxGXYIsYfFRFAeSlBLiCcKXp9SlftdqRuRRlkiaGV0/xxX8mmdDgglHYRWu2MS+dOhtE0bSSQFpMbpINjdkM/PzwxLjfky0gjMqijmSi6hx01GFdklwmMJyWUl2Ko4K0DvcznV4bobgG9w+Fk3V6eounoThX3Eq/8DHMMuCgX0vOCdRd9vivOPcW6Z16HoGqcl1JR4Dkdn6c8LRLCY2Vuw1Gh1G+55wrLcnvTBNAvejhX7TXrJe9Nh2D0gGLyH8ECB56DO5zR8NapRUymWD5efoNQxAyxZN47KgzafEyLF/kh2e0UmiGW+4pMX5lT5jM5FYJZzMo9Ns0N/37BYBgxXFDEoV8jR1lz+GqqHOt5dlhUOe7RVhcGDDlvUfZxQLOR5Ds+oiXo+1ef0p+UdRbHf/vv63+eYcWAKxHexpv9dv3nhH82APngPW/ibEGpSkIVT2Wz8+Gm4XAdHXrZtQZPM74QHb1vaZLLPXVy9chMzZXQSD0uRJIEmI5pUNgdkYWKxLLg1DnaezqMfQzUTxq2bm0msgyy97Vmyfu/I0F1ssCLNiJimbd73QxHnQhmbmJItNzrHLxC58MRfG9sLI4ZE4OgDeQpEX58WcZsJRx0asK7n4MkxFoR02n5V019uev+RvPJIdVANDswocMolqT478KQqevomGas4W2v7A9GoIkiMTNIOgpO+fQHv8+mTMHEY0+FjdA+i2789PUC0pt5oMKgXItOWNVoWXEwKfnwduSFP2q1rma+pIyVMjK/QQPdH1J47MML6Mv2kI5ibfx4Yrsid0NIJd9BkkWX2AteM5Oz9RQd2mewjqsF7L9JVNLwQZnbY7y59YBPFJITe3D3QVq9iIRtXO3VelM10DcV7bgBI1+qdla/h9VJDqfefN9wp0/sxmd/7uuLoLULGHS/5J+xyFnnp8","layer_level":3},{"id":"0f41c3d4-b367-4182-a74f-68659a334ed2","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"调度策略","description":"scheduling-strategy","prompt":"开发调度策略文档,详细说明数据质量任务的调度配置。介绍超时策略的配置选项,包括失败重试、跳过和告警等处理方式。说明任务执行的超时时间设置,以及如何根据任务复杂度和数据量合理配置超时阈值。解释重试机制的配置参数,包括重试次数、重试间隔和指数退避策略。描述任务优先级设置和资源抢占机制。介绍调度过程中的状态管理和监控配置,包括任务执行状态的跟踪、日志记录和异常处理。提供不同业务场景下的调度策略配置示例,如关键业务数据的严格检查和非关键数据的宽松检查。","parent_id":"9f664f1b-9947-4d3e-a6b9-ef1a47485c24","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/DataQualityJobParameterBuilder.java,datavines-common/src/main/java/io/datavines/common/enums/TimeoutStrategy.java","gmt_create":"2025-12-25T23:45:14+08:00","gmt_modified":"2025-12-26T02:12:22+08:00","raw_data":"WikiEncrypted:Ixm4kI/Z7v0V3JxitGlz9d1hvW7Penu2R1TUEKnA4nZ/sXa82q2o0/rG/q9R6pSJrbw0/Vt/KcDypeg1DB1+gb4UmjkdelJ5e0KepQZ4OD26b/k9hkfiT1bCb9j1om4hqua4CI2DuyEODptqw9F59/I8BI+BEN7PhdoeZbZ4Jark5Qz4s5yz/i3BFZsIpTcRqsFUnY8otOT6I9eKZB4EoH31WOPRPwE4Zh0iGZxwki2div8f+WZ4xkUQ6KUzHPVSTvJg/MqhGtCWRF4Jkxv4RBEyqRyjX1qXwWUc2H23nsU01k+bLg6NrTokRPbyKPQf6Hxs7+5+wa3BODF1E84v6o02kLi4RZGahnjyNIL/sHDexUWtavhMUlrl6rf1Kz116lb/WQOqCrFF50nE7cEBd5pmfGwPoVrx+RgwS48Tfa9z8ks/O9lP35PMbZcRm/yW0+w5/V8WEKNAZW1ttZDNB4j3TTfxVYGScKk1lUkUSmRooD8V6rqbGp9h9THDRl6oup8bKHYvllyuCkvl2dyS05MH/mKi/Y3s9zPBjiPS3R6CTgaJaz+8K5YgEnuiX+n+gdYxkFLcwB7EPgYR0gpKyMpkaAlTtWiHAvXY/B48QJMmOZNnDs4Su48HP+MTJWxm7+nFaI8JTilNYYNfqor7tHWZqGU8GZ5APxh38JucGeW6rpc1u2k/z2CFqGm1yApIpZzjUtcjip5CEQrSVwC7BZSNW4cPmzv/s4coCNXQfFeRLhSzcxI9S7Eeawshj7YnKIaPw6Vy5Kl1qBJu4xAk3q1cSdUIc/GzQeVbqdotyAMDPOcgt1umo9ucA6C6cYX1aI82Fmq+Xg3wW4IMpa/D8sXA+yYFefLfC6sxN7Owf/w87sz89hnACLpxMdklfpw7TQixZxMduRgO2n+c9OC5y6vo5t+faGdiGYXr70RcqLX/z4YiIFPNQ83pK9zTOFpiiHze739PwAVvlbCLUTmiqFo654KIpfFNTlQo8cTghobpD7t24iNz5omqvokatm/Bm74sQ/kYvRv5PVOuphWmm5caWLmIZm+BUq0H0joEy+DY1bbJzzNNSDtlX5UWYK9q5tfxTx9QybyqFzRNyz3X3DY7qccPrpxNvU1ZOIced1mxZSZyrrpv9S6LcFORcoNTqvqqnRbD0fv1KnORZlBnJ4pDYIFuetJgBOuzi2whrd8Olo3JziO4ZWA0nbp+Lar7MIQjfsON3GwmW7AKkXf/R6/mfhcHtGX5zPR38+tc7pOgKQaGvwb6y8mVmfUdenEfG1awx5REdtlnB9l8L+OJJFbBEBvNOTLociMUeURAncikgFa+VnS0BEwnoutGPw9oYT8tnE6NtAH63FVRAlq8U0mYCQGKJnrPO5TgZD4OR5KzddN2ab80GG1geIo+ZBSX7dY7M3QORxpJJVzDHeXWcyOspKpspNbPKRQfAK7XAKU=","layer_level":3},{"id":"1ae6ea37-725e-453d-8aa5-a996f78c44e5","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"结果公式","description":"result-formula","prompt":"开发结果公式文档,详细描述质量得分的计算方法和公式类型。解释百分比、差异值、差异百分比、计数等不同公式类型的数学原理和业务意义。说明每种公式的适用场景和配置方式。详细描述结果公式的扩展机制,支持自定义计算公式的开发。提供结果公式与质量等级映射关系的配置说明。涵盖结果公式计算的精度控制和性能优化策略。通过具体示例展示不同公式在实际质量检查中的应用效果。解释公式计算过程中的异常处理和边界情况处理机制。","parent_id":"89150110-41ce-4344-a684-350172827c8c","order":2,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/ResultFormula.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/Percentage.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/Diff.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/DiffPercentage.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/Count.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/ActualMinusExpectedDiff.java","gmt_create":"2025-12-25T23:45:22+08:00","gmt_modified":"2025-12-26T02:12:22+08:00","raw_data":"WikiEncrypted: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","layer_level":3},{"id":"699470e7-5059-4e5b-a919-5b51219326c7","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"性能优化","description":"performance-optimization","prompt":"开发调度系统性能优化指南,提供提升调度效率和系统稳定性的最佳实践。详细说明如何避免调度风暴,包括调度任务的错峰执行策略和批量调度的优化方法。介绍分布式环境下的调度负载均衡机制和资源竞争解决方案。解释调度线程池的配置参数及其对性能的影响,提供合理的线程池大小设置建议。说明调度任务的超时控制和失败重试策略配置方法。涵盖数据库连接池优化、调度日志管理、监控指标采集等性能相关配置。提供性能调优的检查清单和常见性能问题的诊断方法。","parent_id":"a2152a18-ea14-4a41-80d9-cc7645d5b0c9","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:45:26+08:00","gmt_modified":"2025-12-26T02:14:27+08:00","raw_data":"WikiEncrypted:9uOBpMbLX4DyZqW4us3Wm3Q7klXxmeD+JMMoGiSO2oNryWBo1gw9kLkawvxQIW9CASZSiyAjiA/zeT5DwD4S8Fnz6gNK4BTrRBeGikANYgGqLgk0BFTpPBuYK1PMk/gKt8VvZLSk1GBUyr2A2c809JuhXyjkDndA+0gRz7SszVPd2ihSyOWljuEdEpx95nVwg6YCIjPI8FpkH8Ue+C2Ck//coWKRd59XROvSh6ROi7gM1UeZ8n90YWyjRarojkrdYmKybFe7oAjAa7nMPeONB83eKZrM1FxtH1xVb9kUQmUnn1/NVqUsmX36Z/F9hgDlzSSxljGRWJ5ObuGkXvbxZkRI5yPElgKJhbHYgfW1CVNm/ur1BjtKsl9wCLjLo4j8he6+3TBJ9cb+YW5T12spm7pfhzRf2IB4NIeAZpFtWA5rvZ6vj5494w/Uy65jBc3uSxXtF80PGSS9tOB5mHq3XugA6R7+C/v7BP2Iu5vWs8FInrfAdW4HnJigZhSPAqSOSAdqlA7VkQajaqXguNKhYYvWfHr2qqVYKWW+DmK7fh1LWI55ZY2h7PIrT2wpxrshWgi4c5cTHJS6Q5X0k5Tav8BOuaiDjBuSsWnRpvFJB4YpkrVcriXoyd+snK7rHHYffdCVXvkE8mH5quaYmLsqVlUwreWeUmq9GAWlMsUF2mWXc+FEP1DG3YDh5bRrywCtwWszHPgTyGPjUnI4JZ3eNlgNHzPb1HbURc4dgSkVetPl13sB2Q5AsL18gvUiSSEVLRlFChtuxi2hFDLwVGOQeApF1HXJSMpNi3i6xoOtlf+bUmkgnpozGlpGWnRgYJLlW/xFgBnNgZ4mYdYlajUylvbTK74d+q7ngtntYwviAJ7IE8wZ3zaL94XDaDhGhxhvxBhlluDvH6ZVjNZgvWGwhFERpodMRxwb6MSbFw7BM1I7xqmO1P3duJbDgVQ/bLDU9U5V9jCbAaEnYnui9E0O93+YchCsok6vnMqKK7snFhej9Uh1hRl1Mt0NDBeLWYBwnUvEqtuecUCTdQFhLHYwr5yYcvqoB52ElEesc4LA0A4M4p1xpqVgVPGkrgF7YhIW7cLChxsVKdrEZMUu+TnsACdvXgWrvNm0BZMVDSVpngVSD9Pcyip4ggMkLL2fCayGdg4jutoVFMu2rqUNg0bUCkmnP8Lmyx6kfqyeAUKvhXALrLucN07wLSSBeDL7qOH0jGlMrxHnCfmlIy+CqotnKzJbYqfkNxUwr8XcqfUL1E5o2KfweSky69+rdM82ggWNCsRUZDl2Pwk69UoGzTphzoPViJNbj45PeFU5lrGqBg8J3sacj2KlWv4hPbt7mFpJoifN+7Z7jMQCCdkD4dwIuXrV581uuCVP4UJSoIVZY5BDS0KqzbAGpJn8dGPic7cvLcJqNpiak4EaknK9cwa3CiodgN9xL1EAA+bx6VGBzl9LV8E0Dok8RBxh1fPs4WtdVgUivfowrcwEXxTdPFJk+Q==","layer_level":3},{"id":"2c2434ea-3e77-4ad8-9d00-08caa2b60d52","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Livy执行","description":"livy-execution","prompt":"开发DataVines Livy执行引擎文档,详细描述LivyEngineExecutor与Livy服务器的交互机制。解释Spark作业通过Livy提交的完整流程。说明会话管理和资源回收策略。分析Livy模式下的网络通信和超时处理。提供Livy集成的最佳实践和性能调优建议。","parent_id":"20510b1c-4941-42d9-b461-571abbf86340","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractLivyEngineExecutor.java","gmt_create":"2025-12-25T23:45:33+08:00","gmt_modified":"2025-12-26T02:14:13+08:00","raw_data":"WikiEncrypted:FM86MRbIHRcFErydqrYvs7FFrWiQPzCyuijIcmn8HKzD4auhox1kDCDBSFHcytYDt8eFiLMJr4bU8UO3B+vldS5L2uWTf8ROwuy70/pNNVoeq+AcxzN9ZMerzSis/N0LcskTkcjSL2BIzztNV3mz1LCebu4KeCAhUjvhMezxlQFpODw91XblEHdcZhrXNcehDNTMv2gma8hsMwW7hbbV+iRMQdYYGwFBKqWaV4JDv8fC7yT+lskzRPEHAhEf/gEQsUpLgZsHR19hdXXbPJ6FCvcUcOhzbnw06jdh6y5lzDJ6zXFcdxolDBQFPFINOUvh0nbPInAkf1tVdAXQ+1AMsRNNAKHQXo5MHUdL+Txr2rAmKG4QmHaiGgsS3jDJRVsamPq4VVxgKTm9HzegXFdrWjy7shTN8AuoRlHuhgtJDopBHIqFhgv2VGRCT2XHoRSaEZTliqpbz/lROaSB0dTI+FEkgW+SsI4mnRxT3UyWefASzHWw6Xpo96WYnNvAbUBb8ObYNTOEgAqNO4aDO39IG6vvS+pyjP1NvTsUMwaInZSrbeWRnu1+CBKYNSg7ZrcGDt0P1KO+YWUMivsHDQ+//o3rBWbE5rDtgMQ37cNnb9IH+fviIixp9IaF4ic78iWVx46B3eTOM36CMrKohOSd8i+1fyzUz7Z93Gi/Q6EZudlAgaSBJ/F4rpbQc8QeZ1wOBOyclLCFj3m5Eir9JQc38M17coED+ucTf0fO9Z0lGYbDoeq8qiLKMBsjaHdG7ypSthDI9/ocey/YiykZyNIz3Ejfyvi+pbPhGYXIkgt5ednaFn1pt04C8l1YgRRKhsFswll1GHboitsb8CMpyOh602mKs/hY1ZQbvDxYXmWQtsgW08HC22Et53Iy579UzPEYmohixoDVm5qDBwxTiQz3mbxrZA2cke+VADCktcd/tZa/qe1HlTBOpDQ020UKySZ2nnNAd9OlArrTMIFx0UVIdtNVnAqQ3s1L/3vnkznYH3ejcOg3wtLiB5yXHpX1ORRwPvDRElMAKx7eJFbL8dUO4w==","layer_level":3},{"id":"ea75e4bc-2262-4da2-8967-d58c8586631e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"命令模式实现","description":"dqc-command-pattern","prompt":"创建命令模式实现文档。详细描述BaseCommand抽象类的设计和JobExecuteResponseCommand的具体实现。说明命令的序列化、传输和反序列化过程。解释JobExecutionResponseProcessor如何处理接收到的命令并更新执行状态。阐述命令模式在解耦服务组件、实现异步通信和保障消息可靠性方面的作用。提供命令扩展的最佳实践和性能优化建议。","parent_id":"bbd65494-8a17-4b10-9e78-b360cb044f38","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java,datavines-server/src/main/java/io/datavines/server/dqc/command/BaseCommand.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java","gmt_create":"2025-12-25T23:45:47+08:00","gmt_modified":"2025-12-26T02:14:19+08:00","raw_data":"WikiEncrypted:DvTa+P0OWNcfTgc8ZfzcpSIYH1K33EAqOYow3cYQjXSpfTIMCyc2imCbP3RHkQzZ0L7G0WnAZcmmw4AMJBT3dJWbtiooC8pzzbiSeLYarJoeqR9wlhCZyyxMlzAFUhkWdn09kyQzwPBQ+Qu+HS98d+8/lF8Zv/Bub417kbyGX2Sozrazp8pEUL6uSIZ8eH+may2gtC0Y1jqPi5GEWMymMWLf0dpRJ7PK7rGgbaTJ8T8J6CikxWoojCeh1L8RIx5tY5mc8LSUjRqQpTgyT5sahtp6/yLVffQ0i2y6yVc9AVWlsU2b8JAB8JGIbp+6jrTozrbPWIatvosvxYEsRlTDGjIH/GQkqbH0guvEioCJhQj0GyoH9WXR1lD0rr52AhchOjd8GqhJYbI9BHhZZa011tCw9KdOvGaGi/xEx/J8ItZlzC9JtgY/FHsqQTImXSghr5qwyrRAVhvu9wh+V/ePhXv35DQRte3/QUnZcBjTWvzjrUVbRy4s6F04GDwVjhn0xLYutiumy1mLLzn8Te/E/GjudN9Z3OwoBKkZX22NdcNbYVzO0HshD5l3G/AjGYAydiw9hWvshMyvtTB+FQAk3UVrgxemIL4Obik1i1O4dRDPOGtnzNtjJahZLA1OqDo2JdmiDqRKhpO6FwX18+gFsWtM4aLPpOx1fa9k2jcOYqM0+j2moyAkNEGU7G/AV0e4EiDk10DCb7JlUYPf9EiWj54eE55FaaKK17JMsn1ROyvjmJFc8d8CBdiJ7zZfMHlQY4VABVRjwtR/E1LfRU0Nl6aYlWBDX7RRdcDtKIgq25n57tYp7C7hR3ckMqZD8i2OgQ2SQSJgtiaIMre7//RvBCv+9H3Q9jB0i67mIgNafvxC0cWIqhfBBLDxBawT34WjdUoJETBa6EdKHNedg0PyfTyPxd+/7730RF5Akr8qwfWvTSBfIe+kiEh5cUxTJiH/XG32hXVPtpHvV7mJe0aCl7RruiZasGr/mLEGb2NgSmsgZa9nQTJdQXRAG51vvvLKVfJ1HvH8UA7SzwmKlBc+cdGnACJEJVJajtQyJfHFkdDgVYRR4K7E91wS+ATYd9glGIQyMEeLlDW4V4PNJRPmO9iAK4w4DDyJUzqr3Kehpnbiyy0ItzFc1PMOzA6mvyH/MCHBL0nquWmaTqqsGIJ1JtEZgQuiP7YIpWv7h9c69X2fruviZT0pzdcG+u6UipemEDiy5ZoLNosWTkHEOvo1zA==","layer_level":3},{"id":"cbe5c43b-3d93-4d0c-84d5-4a6926379c87","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"认证与用户管理API","description":"api-auth","prompt":"创建认证与用户管理API的详细文档。涵盖用户登录、注册、登出、密码重置和用户信息管理等接口。详细描述LoginController和UserController的端点,包括JWT Token的生成、刷新和失效机制。解释UserLogin请求体的结构和认证流程。说明Token在后续API调用中的传递方式(如Authorization头)。提供获取当前用户信息和更新用户资料的API示例。文档应包含Kaptcha验证码的集成方式和安全最佳实践。","parent_id":"251acb67-6d5e-45eb-b64c-94b11aa2ce30","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java,datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java,datavines-server/src/main/java/io/datavines/server/api/dto/bo/user/UserLogin.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/UserVO.java","gmt_create":"2025-12-25T23:45:58+08:00","gmt_modified":"2025-12-26T02:15:27+08:00","raw_data":"WikiEncrypted:7ZB9yjzZwc/JkOb5fG5L66uGBiH/gTnoA8NnHLN0M4uNlffNXQAgpCx/+5Bju54c3ZYeHzDUd/r1Fx0jiv6KBlb3BxuUuZ0aQ9A88LXqnHSUwbTVCkg5QI31L7hXfyuFJPQkvK1qeVI5AvaRyNhNebLKH44vVsxe3/iH8zccOlbiScf9TWDXBXipE3TUEvNJqLMU71bocDzdA7YFj/QFkzNix9G8L+iCoYibCvSkOZeOVVI3AjiHzlO32LBrnUQMrk2WjC+dW9/8DRfvYSDs1qk8t7vggq9H62SjVHpWgIBx1Usga4/R4txEn0NVE+y6yD1nwYhAkax7reTs0SDsrwJlyQdYnAuOazGpH1PHKcB2ZmUIL8sBb9O7yHNGsmNzVBqp3/XqXcEVC82CazSdHNpAoRFf1SnOhPQSfByjJe1eA/JOtd2khpbES7+YsNb48M0UKkzjTvG4d2SujgAMO0x36Sth3ddmWyThhZfGb27cEKsjtXitBBiLjFE1YxxxiFurCwC8hbTGfvS2awx5BTHDLq+rIPktw5kM86iPZD+wboRHexVRyFbnCNLqC5EMteAluS1Qxm0Ux6x1TOZRCBoCIaVatsZmFgBE6zgIC0u4E0CkcKTuzoDe5wwmHVFT1cW0hF6kt9FMZHfORUTCETwLdhbQ7erz84dKn+XIF6IbxiRJOmx0RygjUoIa/sFMsC7V7D/UT46oAxveb7ZzS9ybID1sXMTBlSy8IpQyRV/anA2clRHMlfS3ryql6Waqo33Dp7nup3sdRKxCOhOBJenVXNY1WgXHyzvl06pd/wOqUJu/zRVmfeOlbKTd/Qkfhr1Cry5EujTTuulz9NiDPPDrCpNT4Xv3ZIGSD6Z5Cd801XqB6es9w1SWkl1vStukXOw5PX7fzyoNYh5VJu8/+cl+0CuzyVRelKf4iUYE+zuMWRW8/0yrGj/ll82JInNKlTMIzuT/v3OWIyW7IMNlW4sAR29MfP6jjIAvGpo+0F5Hn2nnvGrGTmmEcLPF9VEIYgr3j0SqjYoZEexJOfjCSLHtGqntV1bNXH5YqPc8k7/nzR2sMiKsmXPzIzv4+H6XGFPWvIoZv8pJBQy8g4AX17VFJncl63IFDDkVDXevTrDX1qOBt2SQUkz/GZSYx3GYP0EDjwbWICWTizOAhkn7xykgFDJkPuMEJ05b6aakQXsO7UDlDyy92eY/PqRGm7847eo9aMiqZTPCfYO2sH9Gosg9Z9g0FLI7hC0pqKvz06/QuObwoaLFXsoMKs3wxQhc8brD3zwsoOpfjYW5lnaAs1vn9Sa93G3bdahJdFgbrtplzgy2GRo4ai+ebgPP7HdnZJJbvqDTUXB50pUkWFK7q6PsbYN3cOWAU57uKSc0bvlKTdieq6jLbnGV3Ca8Pj0JTFU3tvT2R2szkzDvUC4yoA==","layer_level":3},{"id":"52a2b439-0a26-4b28-b7f6-a29cfdb075f9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Component接口","description":"component","prompt":"开发Component接口的详细文档。深入解析该接口在构建数据处理流水线中的核心作用,包括数据源、转换和接收器等组件的统一抽象。说明接口定义的初始化、执行和销毁等生命周期方法。阐述该接口如何支持不同类型组件的插件化扩展。提供该接口在具体实现(如JdbcSource、JdbcSink)中的应用示例,以及开发自定义组件的最佳实践。","parent_id":"724f7889-75f8-4bdd-94c2-bc5fe8255890","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/component/Component.java","gmt_create":"2025-12-25T23:46:00+08:00","gmt_modified":"2025-12-26T02:15:53+08:00","raw_data":"WikiEncrypted:4Zqjl5aZEo1Vv5NKBpebTgod7t8s/Vk1Ba71XeNCuHtsxXlrFWVSn0D1BZpHSqvW4AGtOj08yLtp8Nb6LzekRQM9JsQ9A8FxXNA5RR3NNnjO6d2Ci0gCpnovmnzYqevcwuEbIVIN5gOI+fXqgVZVI2i5QbOE3x8gsQwp4qK7h2rJdQB7s2Zk75ku0m5lkpim8phZxvmutRj2TQYh3xwGvXnbxbk8hC9mdtdkLN6eeBhFay4Lbs256P8l3Lc+gvK0t23UjODij3IUgLT+SW/AN+nOo41hkG6wVzw+A5aPVE8UeYtHscE8I8I9hmV3QXBv3C/vcpgalDrKI+Z5dMOcMTrpCrGj8uCaPlF9UG3VIcsY68b81pgmq3qFkQ5Pi+qOeCXoWKrRDmVswwsyec5EsITc5juSc6YeouTudtj2b3hEOMwMRbUjTWW9qsrjy9Z864Q8KznVCBnErSfQwKga1uD04QyKnyZUAab/BSewB40ak68c+U1ngmXOH9xgI5dL/PNPjhezIhkD0bTiDkkfFSVfw98dsB56/BquKx6e98NT89KdrUY1EZGukuSjFM0OOzohmm9dd5tlppA9c/0418+YQLMpkHXEnqZ7kckNPimBW6UaafvYN35aTUjVSpG6COWxlPyyECjC6xYyYTVZo3x+QIra3VlBOeAOvf4GhAs/tIK5+RfD+jtwmD77f+XD2AdLxUdD/Funp7UAJNAC5glyPwl6KZBI8G/GdEUxSdwx7yfrR4jfckqFURq1F1tgv2hSIzNd/SniQG4dV8JOQ7sz+9kR9hEpIql/DUZ1qwA8DZvbijfpJY0xEYRJ84B9G+lIt8DjeqRLHYvTSrgaKx2JZkYogCMRhPzxYn0KF176p453jK94X3bkTg39RGG5Uly5jJMPaNdninvajzNd6Ub5w89X2tK8HOPYmGRL/V59ATJ1IJiGsOXwNm0B/9w/i0ygf/5B+IN6STimmxwSZ/EcM8RmqGALPG2mN6lKVfdhZxboQ/ildQwjC0TJgzY5","layer_level":3},{"id":"c9c4ec65-71ac-4795-bd4d-1829346b6863","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"调度服务实现","description":"schedule-service","prompt":"创建JobScheduleService服务的详细文档。深入解析基于Quartz的作业调度系统实现,包括定时任务的创建、暂停、恢复和删除操作。解释Cron表达式验证、调度状态管理和触发器配置的业务逻辑。阐述JobScheduleServiceImpl如何与Quartz调度器交互,以及ScheduleJobInfo和QuartzExecutors在调度过程中的作用。描述调度任务与作业实例的映射关系,以及调度失败的重试机制和告警通知集成。提供高并发场景下的调度性能优化建议,如集群部署、分布式锁和任务分片策略。","parent_id":"ae9c4797-fad2-4104-bb0e-09c584c89e78","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/service/JobScheduleService.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java,datavines-server/src/main/java/io/datavines/server/repository/mapper/JobScheduleMapper.java,datavines-server/src/main/resources/mapper/JobScheduleMapper.xml,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java","gmt_create":"2025-12-25T23:46:02+08:00","gmt_modified":"2025-12-26T02:17:06+08:00","raw_data":"WikiEncrypted:Ixm4kI/Z7v0V3JxitGlz9UFtYuTKfefH8/mQzmARxZqC9PddX7hkwOD/2w47TipEZeRgTkVu0TIPTQJ3DlHrRaNgubejzUBTxpode7rL8x54CCgJkmAuUu7F34AvdJZoSVmffwJAAigDb74sw/LmcLbl+63ZfVqIPC6TanG5hYrC+fy5IqtY/C3lJKoT4GcmBanKqTiyG94KL32MYZgv51ufmev6zARayncnGECIzsqC9l7ZjUdRtBqcvHpNvGA/QbYnBvdlVkGKPuAA4E+rh+832zposkGz7MveDjA9cbA/Rpr2Qk+W/6JbcTJITk+SFch5k0Vi6fMSnSJjQtfo3W5Q8+/4N7nlSISNFa0XH3CoDPbW2bmoVM/tyj0d7CvbqVt4jPoLrrExqiZeuLJni26fb/CEkvEYnrDBsN0yN59wtWCd3cv+LzOIHtPy7/+gyr2KwwHZ31j3YiwbWS9YLPFdIScsQOb9sgIrtM3/yRCNK6P5uUE2XH8NG0rKsq2Pz9EkYv+NXezndrOKJpbSCf2BfmzFOE2OThUO8LUiZ5gVyep+lOG6BeMaxr5rUuwX1e87GdbX41HyJ4NXHzfCv5dcOpSIuDQ0s0E70Mb6JBr1ssESEN1cyRGyW2NILx8VZ5GK6lnE2dA8DRCGiqV3DOeGTznDJCq6wnY6XPrpiKfGZqlZYk4gKCVbGAG7hFCaM8B9wiT1QT7HKAANxufe/LP9tmhT1tNyNXkCxLTqNiyljogDliCyS0OMpogpQ4xRESHruP4V5gwxR7YqXtUkHKk+1bRW3YXwJWsw8LbRw0diVAkddLs3lyzWidEtj8IvxQHMk8QxzguX4r5LNEUMFKo6xTooitjN0UUglkudoAgg8qbxEPJZWgIGbyajhjhs36g/AXPmcGYaFONH273k4YxWE3wr6T0pqGWEW2qVBhSmVLwIXeeyPaHrGwiJcp22HRgKG9KyFw3D8kYhvslAST4Sgqd47xXuHH/6aeXVR/2H9KoJX4z1HzJd/TcvzqDLjolobD9KgDZmvQm43ahs1Zm2CqAyCV6ur0isLN8CSU9dyF/cVOTkvV2y83bBNNBevhY2U3iH1ElKpJeGuQDJMx0DP2KbkvZ2U//LopqIWwiy9qQ8jN14+E5XrCV5YM+BdqPkLCnG7jghnRI1Er3W6UiNGy+OtILSn9BNJBP1AVbJm5IEDlioVD04o/Vo6jdE7lbtJ39c1MYljj0EwqI9McZplk9WDrM0/gXRIV6AY0xl1soaP1o7cU9MIEoUQ346a474nH9ICoBdv/GRf9Z9opZssEEVHa4tC+f5KD3E+OFm2Unkl822thTqm8HEbKwhnHN+QgvIcwhzxo7exWv43JBEpBrPwxfwC61pW3giatWSSS3HMLFU6fdn5xQC6tA0wx3/W9/TSPotZxtkT2UdD44YWFT3aHhkFj1+7jPqEFfQ7Xrs4Fhv6YwaPmIq9/RZSABD1lJHGj/f2AUIAopuUF6OYunyw8StYoZjZS3CTZhg+41RsAQE5dU/h/AG+Qr/pBy0j/fHGgyuZGjCf5GjvXbbucsioPL2dSPHiUMR+yP9/N1h9by9aKNnhi4QjttwxOUwwk/DQbhk3F9SXHJr0CDCimMwqPUQO5MPve7FwpUOD2VBwvA4dt2V+1p0PEXTfF2vJaeP5SiuddUPfFXL3uvx2EGqa0hpNVBj+YbBzeGTldLzIGRXNjyeNYKxkdPfJIiUjUDagFP08y32e7P12ggXQCsAMnQRCyIyL9zhUdGwnuLMSI33UpVA/IU5W+9nUJ23YEVmqjpiYpoIok8jI6zOzDkIuuH0OINymfbtlKnVT/tPycemIq1CmtumxUebeRK+5sQKOwD4ksPrkL2sAg==","layer_level":3},{"id":"5ea4662b-d21f-4335-a5bd-4cfd79cc030d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Yarn执行器","description":"yarn-executor","prompt":"开发Yarn执行器的详细文档。深入分析AbstractYarnEngineExecutor如何直接与Yarn ResourceManager交互,实现作业的资源申请和任务调度。详细说明其在资源隔离、队列管理、优先级调度方面的实现细节。对比其与Livy执行器在部署复杂度、资源利用率和故障恢复上的差异。提供在大规模集群环境中优化Yarn执行器性能的配置建议。","parent_id":"07b63f3a-0384-4d83-9231-bdcd684fc464","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractYarnEngineExecutor.java","gmt_create":"2025-12-25T23:46:09+08:00","gmt_modified":"2025-12-26T02:17:29+08:00","raw_data":"WikiEncrypted:2n/lFAsaMT889x3PgBOkYCjEuiiyPUJGvIO+18ZawAkEfhuLnGTgWx+r7zZ0RG1zXVnjhQbmnMEMk5wpdQ+FHN7Z4zltrncM2LUK4f87ZrOVOv8EmIT7icSjJvJJ0TYZkJ29TJIMZE8KoFfi7G9J92f2IVpJAYcs+lRr6LXG/yODCdeUNpG3Hv/7FuNzzsKDvweVgt2OUWFpA4uAhAQBGAwjQn0MyBw7xTMq0Z18PGw9kGqbOc635EbyoLuBty9Yy6Yceq1uLBIg5KR7yZtxFLJPkXfM2MFDHGthmI+kgudgOjruICLmAC1JW0PNsV+SqT6DeAMJCNpSTrBQsiTwQqcOHDBSqlFwj8xgL8KQ1z1PyQzPL8zSrEaFCZE1pFQXvt6oiT6yvrNbz6q2ScypRTcWuJcM97fW85VrJTAG0Yb+ia8brzXErkODrXBXf9T3shcl4yDQiB+tNfYSusNIKSGlomVzntcXZz/azBgk25qVJLVcs8NdCMYpvLXmpSGnvCumzUXdcwRnqe63pzguuzGvg2e8S52PoCytBZiUW3txfyAypwCG2oYQ/A3oeLzNU7mmvmQIpGcnjTQaKhjK9a1oCYmMTt73IDNjRos4yd83QGDUVEPSIwNLFOiwCkOoBaq5CZYE8BL86m1stpYmiCbfs2EZ5s5+bwh2mHvWH0MEC7s3frdT5AOrH0dojXYmOhF1mvTXjTTBJ+bWAAaBjrKvgOaxDQzZX5aoo6nt8kDkZUHr/f6kzOymQYn811A3iy02Kt9wJRZvtJ+qfsKwASYtklyUWyg4xqrnS5yjdUrfhYFBrGrm9tG89/2RbdQV1Aq72AzUZ2AnhO7F/KTfiLhtDSVSXQwf62hKWf652xnD4N/5So/K0fy/p/ixC7eoMroFsam2Z5zjxAQs2f+P0QTq+RiHZMtj4pelEbA+XJah6+wsG5rrPF7ifLBLkxK24drsTKstWgOjiKa6Ol59JQ==","layer_level":3},{"id":"45955f2d-4b10-4c9e-b1fe-9fa717cafbb9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"自定义SQL检查规则","description":"custom-sql-checks","prompt":"开发自定义SQL检查规则的详细文档。介绍如何通过自定义聚合SQL实现灵活的数据质量检查。详细解释CustomAggregateSql规则的实现机制、参数配置和执行流程。说明如何编写有效的聚合SQL语句进行数据验证。提供复杂业务场景下的SQL编写示例和性能优化技巧。","parent_id":"84f45a10-33fb-4d11-96bc-c2372db645b0","order":2,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/CustomAggregateSql.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/TableRowCount.java","gmt_create":"2025-12-25T23:46:12+08:00","gmt_modified":"2025-12-26T02:17:25+08:00","raw_data":"WikiEncrypted:VrTOMK0P24YINQ3w81Yokdd4o2+YnOpWsl/jyC+yvNYKrkRNjoZWHYAyo6t4QMFqaqvzVV1b2vX6/cJqYxCzbAn6FVtpzYHz/FBBx0h4KtJ2KLniVa8zdvPn+tBFFretZB2zS+nnuqrg85XRyj1zDUtoBrcvInLQo/SHzry2YsA6jsCcZTwPwSTHJHlOI21xQ40K0qK4KFsFKtDba8Aki+qiUxpB8KR/Hnxu6gYBRqpDG4OD5s/sG1CNOSUGLolD2KaT6ojO3d6zWSOTuy+i7lUzMyWyNm0S2V2XB9X2mQhtQUqXdPv/E2tVQDw0omxs6GXntxsJp2XaBwzD/HLYx+OK4yS9cHIWHB7A0tTCm8kas+9F1qrvmw7TY4dU4Mxz2mbDHHT1NMrZhE9dvjnq1KUMYZsiSekknFC3smaIUSC+to6EmSyKT5U89YwsiVA6V/+AG6siCJScpsRnO41/aQIgcT4gvkSGaBKUZhhebviX8LT4el3R+ihzTbx6j6NrGrU/xCpkdqeRZgqlhgqrfBe7jk9kMp56iZhFJGGv/SpIyMm5iPJCvTyTupK9vWk+ZQdijqUpTIcbEN2+4BhoLlucEidH/yIPkt8S9vE3SuYVj6HSnuQIE9hoKYelupL7R0+xRsmGIVMg8HTm4e3VzR8tYOKITNo+53xmL7qDbQVeaUgM5b2cPWm0sQk5fKIlxJroOkiTZK0NAKPc2TA4kbTouA6M8BLrJXIk8wT/3lE4FDmOsoiy9WRH+i5Ao+kTUop3FKEL4oeJxF4VdoM/xE0MYOM/78hywokCZZVhBmv9BneEm6gCxv0S/U8diexULZqbd062gHiMoSfUl+rRj1kEteG/BxJrPWiV13fbRBD6XCVtiuyYFQgyKudQuZfkGLxFtDxbYooGAGcAEV4JZWhcBWJDo1kGJG3m3u7wIOrjVRF1gAmBYVSYCRSkBLKsNrrSqlPwhUN2gU3jaACrIaFMQPxKEpUgQMfnQ4e12TYtpu/kj5fSNvNSi6tydPWOU7/fy6V3duDN/SP5MqKnwfdYUsNVIkfXPaBTPrmKxlc=","layer_level":3},{"id":"2053fee1-5d79-47ee-9bb3-cb3407865e4b","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"本地执行引擎","description":"local-engine","prompt":"创建本地执行引擎的详细文档。说明LocalEngineExecutor的本地任务执行机制和进程管理。描述本地配置构建器如何生成适用于本地执行的作业配置。解释本地运行时环境的特点和适用场景。提供本地执行模式的配置参数和使用限制。包含本地模式下数据源连接和结果处理的实现细节。","parent_id":"aa8efb1b-1c99-4fe2-a451-746364c7e416","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-executor/src/main/java/io/datavines/engine/local/executor/LocalEngineExecutor.java,datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-config/src/main/java/io/datavines/engine/local/config/LocalSingleTableMetricBuilder.java,datavines-engine/datavines-engine-plugins/datavines-engine-local/datavines-engine-local-api/src/main/java/io/datavines/engine/local/api/LocalRuntimeEnvironment.java","gmt_create":"2025-12-25T23:46:19+08:00","gmt_modified":"2025-12-26T02:18:36+08:00","raw_data":"WikiEncrypted:XMvsRjFEcSrjMOAT9RAdm7mSjfy+bKxeZ/O/K8M0cjirmXaKGbIpQtn8uehxW7YAntCNVpUi7l9U/Mp++haLEj6uZxnWFFqtRajoQD4BKsIsT2Vp+Jm0mOSqPLWFwAd1xqX7wjUBKQEvMGQZzZwQO92dj8UacqtoZLonSy4LMcT1/Fkd9HYSIupyODKjT05A9HAvlXkknlW52WVpzyVJdQl961lnec7vzvYZbUNmrJPpfeVPYCPNucJtBAYn0R7TZVJuMfV0dNARuq3Evw5w4J725ibNuNCzxDhKPZD0q6Cpws6/vgsd7z49lcdE5uMJ8BRIZiM8Mq8r1EsO2Oo/Ki3+7rvpCr3lPIm7unJZ9LWGSKrrRR9SRYB0XDDtljC9W1c9WeoBmLw5jaSNp7uKmFvEQfxhKNjZLqxIQsdqCVNzNrXxzVkaQH3a7hio65JKDH6Qi3KWOnBUjXq/TbsnA0NTKup/qEjMalrL3+VdiMMO95yKqYikh38bCkCCwUSqmlZJRQHpFgzE9b4MMWPInn7vGP+OSSCcbjnhzb9/Zi8aPhRWcraUa3pEhLw2JwUgXhRL6do8DX+YYSix0ZaLn+oE+BO0P3wFg4byjBd0u9cSD0zLK/A3gky5WLY+p0sG5FOPFXwkp2hVTXktf5ywA9cwSwcuMbrKMxpF21Kg25Q6rVkPqiOoW0KGHLd0enelhPd/xNdkXG0Q7+jHIFMljAUJ5p9cGEtLwoKbSTM+PVEtPTK+jkaIs+LC/YErcEeQDfBUBGVVpLaIY3OlkJdyh8Us0KiAgN4xPn/KHsFHqCoQQM3mrAKL2fDGKak8vL7NQlDFsljwh1DT50DQG/Iun8sZoONCw451FU5ZVZKvpqP6vALTBkwjuWCQqpAb5YIRuxCFQWbD511bzYIUqJvfY7/vXdbnKFdq/N9N64lbh3bAddo8mH6bnGOjSIBocwQKClqFSB2VK/RfmRaUoEPp2RoP/0U0pABeQxgtQe8KJAgAQ7z/2/MxyM7lxynPgFkIBJPxDRKItotyB376hm5JWPk5BN2Yil35SLfQSrmwucGuedivqJqTOeApw6d9DTr87mj9Pci7F5hbv6O+SR1eHZOcKsS4KkRLMi95fnYUXqGIoqmn+tO8/qO2mjU0s0ft4F7Oi/NURPZSTLlfc/Ip2Wr6AKsThpFccPLdb3vBobZzO4o3H5EjakIG+wapY4gWkJKbzITMcu07Otckec1CxoUEKJ9+ceGBH87DBTIqT4yXpjwRfS406vsRzLcm5zo54rLfwDEj5qZhbHgmWUK8nawYWc18z5lDLWWpQukrl4ZcvXGygejwpVMaPrMtYYI/WWIbmpSk5NchpP6D0emjYmiLBeDTmd22lfLsgYqWjAj1MhxTjorb54qg/wGygjGENCpiTTQYav/9Yr1ORUAMZg==","layer_level":3},{"id":"c33cdde3-8370-4e56-8838-18df48b76d0d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"特殊策略","description":"special-strategy","prompt":"创建特殊预期值策略的详细文档。重点阐述TableTotalRows和TargetTableTotalRows策略的实现原理,解释其在数据量一致性校验中的独特作用。分析这些策略如何获取目标表的总行数作为预期值,以及与源表数据量对比的验证逻辑。详细说明配置方法、性能考量和适用场景,如数据迁移验证、ETL流程完整性检查等。讨论大规模数据集下该策略的优化方案。","parent_id":"a42f354b-55a2-4356-a7b4-d94e20a79fea","order":2,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/TableTotalRows.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/TargetTableTotalRows.java","gmt_create":"2025-12-25T23:46:23+08:00","gmt_modified":"2025-12-26T02:19:15+08:00","raw_data":"WikiEncrypted:aIzKVUnxR6Q2yoHJ/YdAdKcJrj7NoYqMyGyixbe/KHvb+XRW/HJPTCUFH5UgURORBhITNHN47rtvM9Y/agC2s41kCEXa/o5Llo6zatN+oUZgQUGJqg8PkEusO5mZODf4sZ2A6CN8kKgWUCvds6rRBL5Ozo5qd+Wt5/6geR7rGvGpt1AxBjtccuQ484xGlOM20U07ibbeBQwXucJH+HRhxsNx4rGn7nnWqxhn8nJx/sjYbwHDdiv4U3MUUB3Cnc1Y2gQgSsn9H7TFIAl0A05ovXTM6HE8tNWI0RWFmgpkFCIujK02ckmPot/FXZ6lnXDUHyqA4ZC14Xii7u/mou3WNK3r3k4tFlilXjOiw32REWf0C0EdRfiJEMD0YPifmmM6pkuLBZyZo8JuJt2jIYmMTxUzDckm32TU62VT+vHL3jIbvElj2e5kCTT4ZI+3wNWpe5hc1rqx/XSIu56zY6GV4RN5BSrB4r4msiaEq6BteWhpONHQzpyD2xDmqxkY0dT96RS701SwcgswmaYgnIA1unodX4r2p9VLfm64fTh6NegdzK9qWyTEOqpJwNHIESpz36fcZ4btVQ4F85zlJEnBNXYmGLzNHtX7BVfNfHGSSZX77Cyzlcr3pau0eIU6LojqJj4pOrOKTj0ubnIsfrn/YGkL6wCcKbAkVwXf1OBX0QWn/LPJxI0xbtKdKYHwectRqSLQP9an90oc8Bww4EB5b/wsPexQu1PiOWmHBMeJov/8ZrrbKe115YfZIJmtPCrbrA9aS/xe51y83KsdULAePRePHLL04luvU96L6FQcQWuJlZnpYw9xwM2/vV4nalvQzfiZb5D3f8B0sCS2nSJiorwrmnflwoSrUhUWStyjaU15o3gtT7zLYUI/MmgsaIPjrnbg/WBRhaVngaOiPx0DcrOXhyRpxbzyHZluiBM1bnUQQm+qm/VvXBJouz52sq4YY9PC/J31mSQMAsvolaxJCpFXHvXIPwTc8EyRjp6KkW2L675TeCyt/SSYnlRGSAUDR36Oj1qjr3CxLHwmLlDmAQbUAug0RFJFDpKOiU4UT7HY4DW5FBtxYkIJqJ/gc+HxbsfNCI6Vj8eLjg4/1IdWxyGZC98q2id4iKs7zLhLKVQXO4WUx0Y8PaRYkrhxiSlNLOdZ/D94s9xo0H/ngX5lmOOpk+lBn5PXq4aEmxu3Cs/JOMWGoZXj/J6HVrFVFhQpZa3XSnDA6ci0CwGv5a8Mhw==","layer_level":3},{"id":"716ce20b-26af-424a-a4bc-414abaeab0d3","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"告警管理","description":"ui-warning","prompt":"详细文档化datavines-ui的告警管理功能。描述SLA配置页面和通知列表页面的布局结构与功能模块。解释SLA规则创建、编辑、启用/禁用的操作流程。说明告警通知记录的展示、筛选和查看详情的用户交互设计。提供告警管理组件的开发实现细节和常见问题解决方案。","parent_id":"21179d81-91c3-4822-bf9b-316332af72db","order":2,"progress_status":"completed","dependent_files":"datavines-ui/src/view/Main/Warning/index.tsx,datavines-ui/src/view/Main/Warning/SLAsSetting/index.tsx,datavines-ui/src/view/Main/Warning/SLAsNoticeList/NoticeList.tsx","gmt_create":"2025-12-25T23:46:24+08:00","gmt_modified":"2025-12-26T02:18:59+08:00","raw_data":"WikiEncrypted:wM6QACvBFyLP1indPh0DSQZ0n+U8AQHbbghXhTMSLaFDjEtFD0ZqZdAqk1MdI7hziu5TSROaXX4VqTue1+8LCjeX5mePOGO+VVMsLUUnj43LszexxVh2gp9+VKjkL31PvIIXsSLShATSxYT2A2vEEDv4aQq+3HgQMV1YT4LSgrh+dAx3Xa9+fDN1BnJV5OX3n29B8+uKWzq+lhr6mTuykHtOBtelZDcLwEItrYz7d4b4x5ELzMS13OaybGqXmm4dE9l6MAMGbPTDXpisjoZCQkNytKEyFN3U1fG8NA75atS3RMo4zbPsM0NvznmJ8HGlw52nbw4LaA/Ya/M7OYaNGF3NBFW8GjpBpmuWOH8tteiYmC60EvNBKyRUdwAv8CqeZJ3Myu75Joj8g3MWG9ZkfLAHNlBkaA51OGOS5W5L7xK2BjQIIt+LshJFmXQwDz/La4nWCcUy+JM6KTyEAGUR0TPMr4Jv7obvbp4Kj2TZ+TrzqXpqKqFzYkKUaci6dxBmLpfQ6BJhYluuYf07lzt7nCVtpuz7ptAPuhTv9/OebQJkNzQKmyzbZM+BCJfdT84icmb0KxEpKWB0q1j2LG4U3t+LFJIVAVEC/DZYtNgPIY++CEa7LWfd/aZq4KDJ8A89xRDVCcdam0Wy53vYIQNmgi9PkwpH7VUb52Z0Om4tedm+1c9k0oUw8raU2Z4n3VrnPRtQFbBEYbvj6c68lQSpms0c4TQ4ZEreKKPNX7O0gU7nICJp/vi6i+JdxFUcBDrR2xzCRs4+wbHp+6Lf0h7rTmRWIUmlBHPfxqqEXOKaAJd8eGBB80aGs8N2BeLfJvCSOkXxicBCV5Y/IN6H/AaOKnL0N6wEYrdeKvpRkpgNd/4NMUVdDor2GBE3TPPXCValjNv5HOnUr9ysztWJ9N6VQBf+ozgrHJFvdJVB+zNYncpQAwHr0LtzYEICI79OJgMmuGjcYrAmsdEt9kVhYsFYbA==","layer_level":3},{"id":"03dbe7cf-db8c-47a5-aed3-279915fd035f","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"工具类组件","description":"utility-components","prompt":"系统化文档化工具类组件的功能与集成方式。详细说明GoBack返回按钮的路由历史处理逻辑、SwitchLanguage语言切换组件的i18n集成机制,以及组件入口文件index.tsx的导出规范。解释这些轻量级组件如何提升开发效率和用户体验一致性。提供在表单页面、详情页和国际化场景下的具体应用案例,并说明其与全局状态管理的协作模式。","parent_id":"29fa1aa5-5021-44cf-b284-95390545e925","order":2,"progress_status":"completed","dependent_files":"datavines-ui/src/component/GoBack/index.tsx,datavines-ui/src/component/SwitchLanguage/index.tsx,datavines-ui/src/component/index.tsx","gmt_create":"2025-12-25T23:46:32+08:00","gmt_modified":"2025-12-26T02:19:49+08:00","raw_data":"WikiEncrypted:SvMc2PRoWqDcMfdzcPf97M5M5o6Rta+d4HlK3CDc90j+C2evir6CcAH12we4/2wRiTPPvVdz2bf1HM2dSyE2DPDgU2jjxAHOny2ztdtFgN6j2MwzJTx9Cu+XEA6xSmsVfC0pnUBMRFQBd423AVOr6QEBNe/mF/NvAx4ASm7l1N3QsAAS+ack4GtXYzzK5a9QktrUp/hg+IQxs4zToB4XXLwNPLco5WhYZCBE1tP31gy/eq+jL+JxfC+dBgOmZWLjPdtgLKAjuB1ffecLky4xaJ6SWaLYl1Qprn1Srs3vHQd+Jcog3yQrzvylJeQv0wEzxK31M1kWKJUbQLPWGDxriJj9EZJLhCfpin+dh+FOSEMO7QbSMdlgnmXd7p4HDQNgSfFBgL9v0xj0bj/rJZuSkmPi5g0GJEuRAhYkvLGn0tq2yzAr4TGOibyLlhaZJNAZVIu6Ejys56a1v4GTaQl39odmcKTK6onag7JZhlczJZuxb2uTW6LNthnS+A7zvoN67Pr6AtonU3p+K9P21T7nPHBT177Hxh49LpgSMvUDC4wWsf6NndmeEJyrL9m/a3hPSHolupK2R0pzlE2kOLZ1bevtgc8ayQNUzrWH8Ey1aI0N5dkip0/RZ+UyTr9McRcjCoKabovaQm28dJ0atgFvAKH5ZkYrzbgY55z2w+3YRT0sgSSHy4Wf2qfldK+Olb4TZSS3w8rhVzfhHpI5KwsdX9qyGCcr7ZXmfouP+Ra99mFO+dEII0cM26iDybBOPVxtggXXApBHiwNDFHL/J3yH3VEE7CHsgH7EY64hqnyzF3rGs53d/gZr4cgiGxMoNTgSZ4ympYuQ5KGA2xG9KJ3WD3mYYylJy64dd5F9334DhFSfRWXRThFPwPMVgccP6Cy/He6CxJA2xRMXMQgsWcKpdqP2u4JD6zW7gp8FubMHu1DW1ATTFhy029Db7bcDESEnU29zL3wtPevFWkdGTYE63jVx99bggYmvkOThyGx9daEkCnpCe2MtwRSLqoLGXUHQ","layer_level":3},{"id":"82a76e9b-d01b-428c-8fe9-4a08f4cf850c","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Flink配置","description":"flink-configuration","prompt":"创建Flink连接器配置文档,详细说明Flink连接参数配置,包括JobManager地址、REST端口、集群名称等核心参数。描述Flink SQL Gateway连接配置方法,支持Standalone、YARN、Kubernetes等部署模式。说明Flink SQL方言配置和版本兼容性。提供Flink连接的安全配置选项,如SSL加密、认证机制等。包含Flink作业提交配置和性能优化建议。","parent_id":"860d9985-eb7d-432e-a1d2-69e59ae12cef","order":2,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-flink/src/main/java/io/datavines/connector/plugin/FlinkConnectorFactory.java,datavines-connector/datavines-connector-flink/src/main/java/io/datavines/connector/plugin/FlinkDialect.java","gmt_create":"2025-12-25T23:46:48+08:00","gmt_modified":"2025-12-26T02:20:32+08:00","raw_data":"WikiEncrypted:5ObXku8AzOSDfLk4OSAc/u9RVwRdmnK8jlYN/+srjllM0W6L45lMmZDqPz0FxfRNVollhS3dmVpvzCQ2Bc6COsXuQY3iOJ7TzU5sFo/7nj7cRVCSwbEMKVBtxQxxykm+E3rwgbQ5j8HfC6BbLGoVjoJPkX9t4du6lnl+i9vzZho7CbKCKmtIToTwCusvS4aCJG29dUnFU/W+nB+R4jDLkyCTdmT6ZjCp7c3KCK82UxijXOSONVte1NqFPyqPmrgUFRdTUQWpxtj5OzfBFCUiPATGUlyDAXaIMPn4zNG0FfQ/6J/dAj0i2ShKi8X4LWbv/tus9v0bM2OsVE8tuIC99OV8/iNGqgnAWFgwVcxAX6Yxakwib49JSJdEoQD1pecRR4Ich1s0nhz7kVKkoWcj6u/1zTYTHhK0BgTV5Z/hpvgH9dyNy6vhBwayDPHgTRaWF8N+99WSpA+LbNvNi0++PPADXzcZiXoy1puHGQtBPZix36KEZobLw8NQ+epN0arjPw4z8qZLI3VSYxlXMufXPv5K67TPSPlkH3GW0h9o8IVAnnsmuGpG9YKZ0ENPCjE66/ZwFvklXjWaF+ufNhcSZ7efMLPvmFweOSSS6ugEYgmbvxg1x8gjQvETubkj2bRiXGrRI6NoNYUV22TKFv2h20/UCIIowzct7lK5z9mJttY/z8y7pNN/zXIMy3MlNhWTk/IL4dYuMNOkV1s2ZWakGK9Jq2KQtvuPTeiPMtKaK1tJ9aWB7b00IOytoa7fwRSdfRjc6NYjVzmiuGjZjCNPwbbKp6NI/bw/XE89WBZcfA6CFSA9O/U4xahTxJkz0Wv7eVpTIBpxhFdeci5vU+jd3D/zVhSG7ObcFNLeo6yNO1IMRRbQ9sorSc1rRUAN2UMI5iKlJUjHk+DMhbGRxepHl1A2rn9bRrF6aYLPrwWMOUxvhpq0rIDaWVGs6zu/jSmSTiuZ2jU77nJi0Spn6vkjdRAmdaNAMyvaJo4fGsl3jATle6hh5Oc0FPpxMipTVO+A0E6ZgIk5i8uYtagM81eu1ewIDxM/6HR7NFAI2gatBnibseDNBRUzaxFG0McvaY3GIcah5/lMSX2jtAcRu3fIK6+t0Y6gRf3T1vthJtARgYVMW6HXokzKF3o50Oa5r6/e","layer_level":3},{"id":"34d65e98-52ed-4aa1-83e1-de9389ed10c4","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"云存储配置","description":"cloud-storage-configuration","prompt":"创建云存储系统(如S3、OSS、COS)配置文档,详细说明如何配置云存储访问密钥、安全令牌、区域(Region)设置、存储桶(Bucket)权限等。解释不同云服务商的配置差异、SDK版本兼容性、传输加密(SSL/TLS)设置等。提供云存储性能优化建议,如多部分上传、预签名URL、CDN集成等。包含云存储连接测试、成本控制和安全最佳实践。","parent_id":"1e6b21d3-ffbf-4413-b2b1-7835661a6c7a","order":2,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveDataSourceClient.java","gmt_create":"2025-12-25T23:46:48+08:00","gmt_modified":"2025-12-26T02:21:21+08:00","raw_data":"WikiEncrypted:42GucIVlAI9L6q+fifwcxQwHlm0aX4FSaUMEDmOf7a+AHWG+XpC80hn6HZ7u59X7okIEwsEETbAGK7b0J9h8Cb3Tg36/L1UzK52AF6hM49Tek2GQrfGsZiZglHvAW+qPKGbnR25qEyk4T9qWiLrPaP7wPe1w6cI6uadPvgNPbo9nowRB+Uzb6N8VhAScacvaiSiRuwW/f5NI2OVwHNaM9E4lNXhw0WJgo+W71T4+bUYrXZBjbS/pa4MZ0CaNqYfhH/xofCJW741HDLH72/qoHmdb7lN43O6J0AssqfBfgvXW+65oCKpsvIZ0rlIQB4tBhpGlQK01oNg+lCZ6Vmvc2lwKjufTFZsFSPdHCDPuS8vnP8hkrqbecXnjNkADjmuTsb4WokjTNDj/YXocx+fkmJFKqw/wKQ9ODftcC6CUS3jtSDjvpR3CDI1YTDPKa9IJLYi4nsSBFe0FxVGPthHT5jeW5gYkHY3aIWj1VH7FuQSM1SpPtdjGc53EbUUigpKb8WrQizMQak7iQMLxfzlmy+bu7EFgoZws+o8P1EpWboNd3fhPYs8tC25dfpxRDWAf8SSQ3x/rLFb5rMdcgHXuoAbtsbytHYnZuFVR5a8CDzSCp5cODLowzYKSBmmvcluxmCoskPwMO0hEWtIw7/xp+YKkbOGrm4syJQEKiZJWXuJu1Rl/+kQ1JJ4MA6qeYDsfDPyIa9phCepPm6z9VPezlKVHbbuV5BylmgFsgEXRIMjXjc3tBIS9/ibcXadOGEoqeD7sfy2bE29FeMCjDgek+QDFvU6A2n8Naxs8kY/ITbU36a1EviT7i2kQhMFOOS8sFHjGuYQe41INSaCME/C1Xj4IaPP4kwIea8xEhn1YiSEUYdlbvWxwgQbt1CC3anyWgjwneywfiqoo1JAlLU+oAZ0ZKgocsv1WCmfFtJcPA+hXC22aLCbNpriwgOHSfMOIu/o0zI4dwr16eRKxmfyQ9i+v9t4PgwQkxLi3dLNq4cV9QfK2RBseU6gbg1edk0CSH5v/QqotEaVDxr+wmUnfOd4ktmW/NZMG9gtNnpI+E4pn+D4A8HVNQWaT6zW2NmMyOmHMKuAqquYBSBCwVCIu4A==","layer_level":3},{"id":"11049f94-bae2-4321-87ea-f59868608802","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Oracle配置","description":"oracle-configuration","prompt":"创建Oracle连接器配置文档,详细说明Oracle数据库的配置方法。包括JDBC连接字符串格式(jdbc:oracle:thin:@host:port:service 或 jdbc:oracle:thin:@//host:port/service_name)、连接参数(如oracle.net.CONNECT_TIMEOUT、oracle.jdbc.ReadTimeout等)、SSL配置方法、连接池参数设置。解释Oracle特有的配置选项,如服务名与SID的区别、TNS配置、Oracle RAC配置等。提供性能调优建议,如连接复用、批量操作、查询超时设置等。说明如何测试Oracle连接器的连通性和性能。","parent_id":"82e5534e-5b78-4582-ba77-8590166e6cd0","order":2,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java,datavines-connector/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java,datavines-connector/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDialect.java","gmt_create":"2025-12-25T23:46:58+08:00","gmt_modified":"2025-12-26T02:21:36+08:00","raw_data":"WikiEncrypted:ZW4vMrVuodrLqpjtrVAFC3oyBYKT/vHRxaAhSsvV7BDriEzlOffqrrjEFKY9oshtrOLq2O8iu9XnArR1dGDzzq2EvB8EXCkTa+7XJIg5HDJlC8hak+v/AhK0+NrnxnCC/0x5g14lCGH1qUGHUaxcy33qbDPSZ5ka2FXKnnYz/PVb6ZvMcNLwKuYGGwMv7pb9xuJAI3UemiihOESF0tjIizthoC1HJMza9g3Sx7oFbAoQFEKtfHv/jDH03loYyd01XHJZu6whaKi6U90uAcxXDvwlvhpmbFB/L2Ua+dDllB3YSjC8NUcNK7CnT2ir4V0ScdK0ryrzdgBiOmd9p52PoX1ohcIk98t1IR6WezAlKjhj/LEsGEFZ8v6EgeLLBfdXRG6uOjKMkif7Rh61p5lTpz8LK6O+19/qXFZRLwhR92BwybQ8KuiRE3594vDKZWFw0+GRVM/9iTN14iHSfhnnLgxP0xTNXdQIrc35JPn5P8fRZliadm6f2hbiZudS39UWF+vp0HNSlxqIV9YwAirQKcKcJHjof8VCxF5pzchDYLdsgM1KpxiJTUuvWmf6YsV4XSdtPbYyBcPkrAZxSYf2hxzFw7QTaoUnYMfs0gYQC2NOCbHa7X1MMr1StCYsjfLiiqp+jqAjXOIOwE5llUJFwa7pNYLulqjz8oGyezC/1clsDMVByTPyhb8Qcr6HDkjvIvmY1esYmwgdhabdhUbbNYzGHG/gqi9ZkZhWDViRPui8gd8tdpLJqEsheyPo1WyuwG5cqwY8NyfEgb2gORIOulmQLiL0FRChwJyGg5Sty8At94cz/v2TeNLaVFJEHgpX1yjJmXuESL4Kgs4MpEWoMLdCTOBmr8KTNxUu900FFY3RAbZX8m1+TYBhzDat6plZlPtXANiKZxVaB+ZblGwutqjUZDBKug0Fhp+0b7qoImBkywvt1daDAeu0rV+n42hhakhVdKCSNtEgTEEoT2Irk7HXIS3E37wxbYxvdvzM/4jdTIIZUDUSF38KQeM97PAFXv+AEtRAjtrBhRTUpEu/oD5pgc0IUvA9HsOGNtUEbUTbzv3zmin5cXDI5M8lA8NonO2Xx2Fw5MFgutvv2zOiTWxUGjXWVvOaTIXz1VKPn3l1ymPrgezmC+mlOgPyE9c5eUy3y5cEKzIz4S5KLM+NJc67G8roelaFSnMKjxHCGlC07sb0VI+ULhacHYXVLc0uPpcvw/Gw8C5aiaUmQyKk5/SGk5ryoqX36M2eznl2gDclhdOPm2m3invfRiHc5+qFjEKoJY9+r5zpx8K73Ond0+/hBcO/Q5P7xCgt+cpnX9LpMQCxAaPmjSmFTZcEDwv3C0cG/Chyt7Wzt5aiyAlmUf+uj0aqFihLzhWOmHfSl5huCg+5uxCfUji28dBH1uES1aOQgaNde2tmPcn6PvxJML9pYd88381F9rh2bhPyzDi9TmaGtCx56V3DAmsM2kfXXsGZCtGQHnKev+WU2x2gYg==","layer_level":3},{"id":"7f81e91d-4a21-4be6-b32c-a343de2727d9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"错误处理策略","description":"error-handling","prompt":"系统性地介绍DataVines的错误处理机制。重点分析在数据通信过程中各类异常的分类与处理策略,包括连接异常、SQL语法错误、超时异常和数据类型不匹配等。描述DataVinesException体系的设计原则,以及如何通过异常包装提供清晰的错误上下文信息。说明错误信息的标准化输出格式,包括错误码、错误消息和堆栈跟踪的处理方式。通过具体代码示例展示从底层数据源异常到前端用户提示的完整错误传播链,以及重试机制和故障隔离策略的实现。","parent_id":"8686fc3b-bec7-4b41-ae35-31b1eaca7987","order":2,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java,datavines-common/src/main/java/io/datavines/common/exception/DataVinesException.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Executor.java","gmt_create":"2025-12-25T23:47:10+08:00","gmt_modified":"2026-02-05T02:06:52.2906492+08:00","raw_data":"WikiEncrypted:w6XgJEtEYWza8knh3RrbgjvEuPgBjpwkE4DPLmV+CVtyoCs3lt28u22Rmz6mrITXX2buQWe5a/vRTBtJK0NdEYcwz6TAQygvUQTkWAfxBpodK0SICZxB5GM5vBDivcjeYs37trNl+SfqebVHHZGvXfczpQ5sTge4UfxbG3pVht1gT6mL48G6xjDnJHsnCCBcEX7FVx1+ks/zuTdqJ0M/r448zVHoxxRXXtYKffynX9JJkjhjdXZhIaakqmpmFSPn3JENHxmreMF2UclOft/ylzWd/Ww75vQBu+eNIyTwn2AqsCzhLljXb5jaIUH37Y1D8O/OC9xAxC7uB3mZF8sBZCX8FY8StaKgvxoNLZmRrP3W9KmK7dwMVSnoiwbXfqGeo9Zmli+/uN7ub/HNcPz+pE/llXfc8j8B3xXL6/4bzbo1nSH5pKVJ7kf7VB9q3lZ0WHH4Y3+eK6G6oyLCcqZ7wc6o9qGJB29Rvyta0csAlnHzL//mZef52QZ/hBSGezw4aUTlMgQlYGCqtqJ+BPQYRENSAl7q+UkVeKahYNtGnE60dn82Kc+UpKgvBAaY0SH0m9IlunnGAuqSdgzbG6HF7sYSgPXWghbM5kosdibU9S2iCiagKKV+OteGwQU36+AFKdBwDAjmlv1JZRrxrLg75phuoT8SZIPIdkzTVFAvpeJOFIFF0Fs8oCsaHie3SYXNToDi5a3QZnYOvJBxAr0eGdBPIzdb2rLqq65JJ4ipdpSkSbUuhXJR8oBzvQfRCc0E42x2wqbvXxWKh6o6mqUBipofAsEhkmIlIyHz4rBXWClL9C6g9fXdHhg2vMCuSV7c+boBfOXfsOfmw6u1pg8yvfc9i/JvfXYY7ZWBDhHuRilBdXwEaOjRMCLIymmtsSKyNk53LN6bAF1CLfMGXNuOGuauqMyXCQjwEDyJgRjVHfnQ7njG3mVstXCKgbJRqCwXVc0WzZ+WqBlxhpclW9Iv7+IN6jTu3VqukJBHs9mNtFScgcvsvyOA2UQUc8fLsE7p1vfo/mQa9YyXkz8NCOZgaQpTgTLpJfsui1EjGS9NQnBX32rl014x6fa11pkommbR7JXVodYuK76xqlqP+OyuwjCwnpsy12RYcBk+Up73ximHmU4jGCAydwFpgpxxystks/skzoIvqEOxcSeuFAFrczyAs27RsqBmCa6GuuVX/eMuz7Pl4uM0qV3fNjtziTlGj03ED/cgWPqO7rqpGa6B5KzEc2mL9fGIIO1MCIEQOcg2CaCOUrdiRN+1nYYs9M7rr+GUOzCxhBsnahoIke9sBSMt5R4SNbKbFod4itOXGMeQf0gXK+RNL+7l4z+Aacc+GjxCuDxMi8C6hU3ntSSwKn9FCrizRM1U6gZMadLQBeuOnY7A0kmbRbDzzk47aet56MaYZrterPw4r7IYmoDNszV14dbVs4CUbw6dntJ8j7iHsb4khbr5h9rp5WDglVaE7kZ9Pp2Ay9eHi/uATri4a0DmJopbIhe5jHqu8cjoa/w=","layer_level":4},{"id":"c35785d4-cafd-424b-9de1-d536b2b5016c","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行触发流程","description":"execution-trigger","prompt":"全面解析任务执行的触发过程。描述Server端如何通过DataVinesClient向Engine模块发送执行请求,重点分析HTTP客户端的配置和超时设置。说明AbstractEngineExecutor如何接收并解析执行请求,包括任务参数的反序列化、执行环境的初始化和资源分配。阐述JobExecutionResponseProcessor如何处理执行结果的回调,以及执行状态的更新机制。通过实际代码示例展示本地执行模式和YARN集群模式的触发差异。","parent_id":"bfcfc439-ddb2-439a-b44b-cc168804d1c9","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractEngineExecutor.java,datavines-client/datavines-http-client/datavines-http-client-core/src/main/java/io/datavines/http/client/DataVinesClient.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseProcessor.java","gmt_create":"2025-12-25T23:47:12+08:00","gmt_modified":"2025-12-26T08:13:17+08:00","raw_data":"WikiEncrypted:jMgId5h0EoZtwilIIkOV3tMQfwfqDjkSzauT4yWrORDka8LvVBVW80z9vHrxXM9NjnGVcd2cP5WwmFSsFu0Z//JGknQflq5tv3R2WMEAdUGEHR84Yrf3usQ++frp/rdwDijdQYyiry9rTNJvkIKKGbzPLYfAKlLC0ycTvg0lCGDL/fhCVeOvnl59bAii9rBkNhAXAVbWjxbhGz5Wr8hOA7jB+Aw9OpijPEBMclui/Jxn27yTvJqBkMifdLC4uxhdKfiKTet8NQUobkAVTI36naJqas2x35/U/JJjhaAzP+71hX1GrpWC7ymrV8WnD03cHnTYjoELTlCogxT+ZNklrMu4NPTv759tuh/SE8H3DMqt0ZX9f/xuLhMsv/eDuOZzxnrLPdMOpTy/SHuTK8bazCXNtujaCDJSiz/jsx8JLrW+XLdplXGy79ws8pl7vL/NAXa7k5jkdoYQwKNxym1tNRH04nzTF9cRybrGg5ZQMNNvNhlp4z5DqbQTRVda9DvNPFazi4uhtTWuTummsCWoR5THuC/Qj8FAV3L0rMfaKndGC2IkWXpBJqBG/dk1FaiGW0RMnBWGooqFHnNWU5K6+g87B5lecQJC1fCBVF/ATdKXDUdTZDBi5tDl0v3tsvFXzr2kV01Kf+GPysSjTTg5DyxygQ6wxRMnh6PNBb7SOyquhUQwALYjl07susvH0PCM9XXAVRFlvPn/idju0bTwgrBFYs8ife0D4buBLqYQ1qbV7XbKz8x4j6PK6iRFw4bGUGe9vehI3iPDb0qHj2dem+tPI9eMGxCYv/FV7d8SzOIJv9z6XtxGEC6PEhy/k85DSy3FuVcY3JNzHvNUdGsaznthO57DvRnpt8tC9jXGfvA+FYL78EhNata9Lqs5GcgqvldywD1cLP7A/YR5C3WAhaWKzDqodZ55iGXVW1CMz13PkTk5lFEIOIq6Qr8ORRMxfFVmJVJgcRhCG8tvTKFSM89WK6aTRkZGB9Xil2x8TCnrbuhv4/mAnWTM1t5iu6wH34rj5xLIHyQZEELrNKYF3KXv004Jb4ERqao/wOeTICSUSYyubtf2N48ObiKNhh3NDSN0cr97oHMFg2+apH8cbHtozdA5RKzm4RagjB2t28iOXEAByLYWgjFcjEDXOSBWoVwhj0Mv4H21WgwURI/pMuwwGWoHEMDkQrdHa1eVJBVGggR1C/G4Vw3QLFZQ2+ZttHcgIxjLN3IZjPuvHyg4hQ4il5kIUcuv7bKV8Uw+0CDdp4JgQpCDpH5+ysxMaJJ5kk5cgc8QYLeOA5tpBDBOUFYM8iRiL1G/Pq36SyCsnZMR5oVWShuX/XGhKpZN5ynGCB7sLhaJvdq2k3wBNaEC3wsa+p4DLYgxcOOGdTHxBQ2GpHzHlnDgVOPITZJZVke1tFsDuplckSPv4uk5L+5fu560mfwkxDPSgZIcAZLw3y8=","layer_level":4},{"id":"bc3ea374-b5d2-4353-95ed-77e764c7f7fd","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"异常传播与处理","description":"exception-handling","prompt":"系统性地描述分布式环境下的异常处理机制。分析LivyTaskSubmitHelper如何捕获外部计算框架的异常并转换为标准化的DataVinesException,以及JobExecutionFailover如何实现故障转移和重试策略。说明异常信息的分级处理机制,包括临时性错误的自动恢复和永久性错误的人工干预流程。通过具体异常场景(如网络中断、资源不足、代码错误)展示完整的异常传播路径。","parent_id":"b282f234-c03a-42ab-a5ba-d212befebae0","order":2,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/helper/LivyTaskSubmitHelper.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java,datavines-common/src/main/java/io/datavines/common/exception/DataVinesException.java","gmt_create":"2025-12-25T23:47:21+08:00","gmt_modified":"2025-12-26T08:14:13+08:00","raw_data":"WikiEncrypted:RgZcxlS28ITmDGf4sH7fKcx/KKgHynIcKtHjdIlivuEsNVHfgt/LTwrapHEjyycQPxfk6Paa4paY0nPi2OHWl9Qjcgb6uxpL0Cal797igU0HRatJBONMthIAPgxAI6LTMRILEPHPIuJcNCDBCpiRWOxwKVbZ73z/UkEbSNX495wNmb/OQKMY2XvvLlx++J8ycdTidES00wpbA3JW3qIkVCJDoMlfyoEjy3hUrvK9PWhHJ/l85k78ZRBBVtWe89z1c36YSoMeA5N5f2483zfBnXA/F+GOAXwDVeJo0Egrw7vihnBOmhjNgPyNJFWNAPadUCIZKrKmmronnkn/vfkXxyXgVeF/6YTnlIhhhoXnVUOoWHEgSWxF/DV0yfEzucb63HmMHiSLJsO3Mbz8H7zg97i31/bc3pSKHY7iXGLjDjP/kgGlyXgmEpXotMxWMQz3QifDmZevMRqOwZcBx0CIdK2MkbH7n+Oz/p02N5jK8h13TKkeflZ8TFhGmUWiw9NxCYjIAyjF1eMhpoLvHZlR9Ed1tElGkEJhxJ/d9v5xxfV7t/lIXurS5yzR+9J0StG2chYLz7yhc2rmT3a+73ifQm9uNKz25MnWgLqxF+Ws3uEkLa5N9jpmZNAKoqlw+DQGZKgK6V15ptQux0vMCshkBWPakmDOh7Cl6lsWUQ5YizJ+RgGgvsLD1nJQAr72BVxqm5XkTaGSVjM81dbrldhn6eePD9V3J1UBSwFciWehzpUR3za6VA2EKrpcRnPdZLwsZqMnJDax2u5p1obMxP1jkYqBNkrr/pmwesT6jS+lixxGyEQG1WZl8gu0w4vNaQ4c/UVHYzEh5mVgMoIW8tsBl6W0RU9+SvAZBHwIQ8aKnPZVGGcxu5Vj7xcua6USrcj+3SrSadjy2RLe6CQY5qK4R6SNOuRE5vUZ/5Tb9Ogf75XrNaNgARN4J5hKvKajtvpgQTZR5PYu/I8VKybZQXSsh7g/rsXqZ2IyMAot3yZ+e+v7FbDTxF8AD307v5C7Q17Yy8jou8Gmq3TMPmOsgY0O5yy6Ey/Q3KX4RNbvDxg6tIfyzbYuss8tq0WDnFIsuLcrnLHOSOx9kw/Z/o4jtK1aEKvyLpTwEy1t6oDCVvu7xZnrj+wdowVuV9eTm0912mv0c+5PDYwDhvlHE1qID62YpXhK6ruyEwEeSnkzD1b1MQ30Mc970oQoUv1ST+WeiJXAbOi7X/JPZ2SmwXSkNndv+vcR2CJJQ2h7Rd2bAYqJUruQQT1uJ+iFOEYax+RAz607jHM4ujBmNtH6vvtdjn+iCPcsqcHH+TSTKBk/QeVm6IdOOM6NJtZrYBzkEakyUdH8phikoRqXWZa6t53nEZPFGA==","layer_level":4},{"id":"93352bfb-74c6-4843-8c91-6b3e2e0e11d3","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"业务规则检查","description":"business-rule-checks","prompt":"开发业务规则检查文档,详细描述DataVines支持的单表列业务规则质量检查规则。重点说明值范围检查(ColumnValueBetween)如何验证数值型字段是否在业务定义的合理区间内(如年龄在0-150之间、折扣率在0-1之间)。提供具体的配置参数说明,包括最小值、最大值的设置,以及包含/不包含边界的选项。提供使用场景示例和性能优化建议。解释该规则如何通过SQL的BETWEEN或比较操作符实现,并与执行引擎集成。提供实际业务场景中的应用案例,如校验产品价格是否在成本价和市场价之间、验证用户年龄是否符合服务条款等。","parent_id":"0119e5f6-79b0-4d58-813a-14a0a719454e","order":2,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java","gmt_create":"2025-12-25T23:47:22+08:00","gmt_modified":"2025-12-26T08:14:37+08:00","raw_data":"WikiEncrypted:mHLzoBKW/ak+KVdbda4A2WTXkE8Aw0X8FBHjjUaBiTTop78Jw2xsq4Jpt+Tlv+GZpsUdt2aa9uTtEzApyhDJ/xdNqOEm1nkGGxoNlXN7iDMzxr9mmsbTLPBGqKGSawuqnKIjmQXEE7pLn3EJhcj4royB6UPAaSCSvjVCaWvGBPDvIFIkxrfZCjTzpoj83JnLoNoYazF/USMBU+a7EMAASY1WF4zKb1D+YH/mm0O72uZd3bbtEdLIXrjKZanDnvQ8agkU2kLP31JnPa/6Cdt6eBMMJ2ivSgC+goQ/3ChV9TceJo4P+xYzm0+y7mILd/kvUZj+Ue0zqlk4NRN8jJosqQ1GXGhj4Xlw8TX6otnDJ1LyUC0eFzQpGNG5A4jefSOiyXzZmh4CPTUVf+8BmKbMyyQtiMdVwC9OW6JA5UXE//JqIdUh+3FCEW0F9Lr9yfdoXO3AJlnd8y48QXXR2+pZ152VjvWsH7sT+K03KCCe3hQFE5RaLj7tZgo6D1HBTFZdoMCk9EvafwQgSgcX+y/4J7sq5AslX88h8TWCvlDQfPj9psPKUhAwqmHj60KiSlZbBjpxT3oPehQPS7BY29y9LcZpH67ckIbzR1W/m+r5T7vb3JHSfzx2vtDGFKT/VSg9C+r4WQGd6h0+ChBEWgdIMLgQmylDZPszQJ+/AABscoGvobuf8v0L6gFVcwAepQHrZAt6flSG16/Ygm02QVAqs/+/YzXJOYa6JL2Z+o3B3783kMpVxuCEEk0NVTWqooAMNwB8eOzVCq3sDfoJKbzHklQiWjAIzrm0Cjp/l4PTUfiWhEYexZUQDtPvITQXO9xMBdi4ELWSF5Ze6UqZajLKthT2w5/mqqbxHyL8cqUDozo2qgfEeFtr4cML+guHwLXp80Mf48WtAHNIwlB/L22uSnfUy4jqBzs5WCx6bUKF36Vmg8z2uSlk4+sUjE6xpxdOysDU3nXfo9rgLeFaZ7TyVpz1kMulNuvJ0P7bzc2l69ZAG1GTPIhZ+Qe1+G06q4edha/XTu3FcBJHtIgHGjKHqdHDGDYzGOcrKBWhGtZHNlra9imKBfTVsk8ZnOppETjx5iQC0ZeTcu6PuER1y05SkqU0whFsIyeyDMnbd8oh0wGNL3ZOI3SIe4DZHBknIhp7n8njv4aL2KoE/sTWm4hnLmEfyo+URuY9kwZjhVyk1GENKH5irp8621nqvvchXprgfC5MM3XPgViAqKZ/SoZSP4xflC9e1FvPvYqAuDvSdw0vV/W34fXi9VhxTrIxTfveqXvjSo1B/DZjeJYst14i+UWRDdF/ECsegBUA6smJ/FFfTyXZ53LgPIAQgylY49oPt9l8VHY/Yj0tHA7I2FBhiP4buhEZv4Y+RKSrhBe8pwk=","layer_level":4},{"id":"64444bcd-fb4d-4b0a-b358-501356c800e3","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数值范围检查","description":"value-range-checks","prompt":"开发数值范围检查规则的详细文档。系统介绍ColumnValueBetween、ColumnMin和ColumnMax规则的业务应用和实现细节。详细解释范围验证的SQL生成策略、边界条件处理和数据类型兼容性。提供在金融、电商等场景下的使用案例,以及高基数列的性能优化建议。包含动态阈值配置和时间序列数据处理的最佳实践。","parent_id":"8195f94f-7c42-40f0-8e98-ab1163cac8ae","order":2,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnValueBetween.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnMin.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnMax.java","gmt_create":"2025-12-25T23:47:36+08:00","gmt_modified":"2025-12-26T08:15:48+08:00","raw_data":"WikiEncrypted:TWxnFQs6bu+NM8KCVV/VMu3TN3EzMLNAr4ilRoK3VpMU90PfbhnlmK07+Fp2rd9V+0S7rHEVT95fOPzd2mddjDt2AdHL1G6HrEb70iwJN2aWlMZOUmULamwiKpFK0dhkeNNVF555pl5YK51dw6JL0guJYPjbtTUKP47WZ3bTlaBn335xB5bYpzsuRnkWafGLlKqG/O46IeMCmrzP89kB4v3tY3QZtJSrFYI575wlctEk8hSgHWrZaWAT8Yflrg6xHSTuyRzGw4GtaBdUGbaIStH90V7jY4W/knyvDOPe3/PVF0oGmuqYmBSoHOKq0Pw6UyKToA4Y/4NmwrSb3UTzVprqVG9yHun+rvNJx0FcYuY/AEORnSlrBiNqk5+dW1hr7PK6uRp8FAGj6/Lw6nHjy0wr8CwHu88RMqs+v8+Zc8wBMaP2m2d3IFbLKGsV3KnfiSZ5IhNG8PcdLJm9LpYiJs7seh81XGg5w8xLWUqYYZEOntu3fSWmoQ5obPQHNFPsjGzf30oFwyKT4GPOjRp4RtvdYHKp++cuKGkDONSZOEbDkBykJiGEobnDe/6ZnC+LglIzBcBI3Jom6czkswGk0HIpweENHUj1vcV7nqwrlwDyYJFucT+YlSHguqRkwmTFkHfAiaDHpkvFCP7MAp0giceM6mFnuXbV6OfXejfWUWEHe6v7dlxJkbwImw0srI9lRLeHRaBujGC6agpaXM0SGaROpG5cUxpREYUZXPZyKTZp/LajZrgYe2tJ5lvLVrsnF4+YnTAJaHrMbCCM4FbU/yB9M5501xMFjdk8vsyz/FabHmAEzQVrfHX0+vOsAINeWt6eUjmOryGQW23MuQirT9idfAv5UQOPqK4ePpjXWnH5IIqlX1fN1tYqhYhVqUEn57WdlLTwFcdNJffIsns8CYU5Asl6NyRW4TSFQs5ivXkb+ZcjSbN9YvWMQc8ef0aiHES1Mv3GhL2jckQ8MnScgIiLR8jU/uRsJ59uIX8FSPeqWM+G1JUWHiuXMffR97Byq8Kreaobf1ozxmWh/c7hLbi4zT1EEnzGO32iop65EYbTIxXwtaTKFxZk0oYKD+72UvKSqjrbtN/3dzPw0eAcGEQEO5bSA7+lO8OHP0yiOdZlAXtDaapwoo9HGXsnCVr4RBn0SNiJUgSV95XPib61pFQTUoHAa71AXyD2HupVYAntupJxLhMRtteb6vjFDU1Pmf9SFYobAZm7ER+eqffMuw==","layer_level":4},{"id":"3b8d6652-6da6-44d6-a1aa-52533177a601","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"月平均值策略","description":"monthly-avg-strategy","prompt":"创建月平均值预期值策略的详细文档。深入分析MonthlyAvg和SparkMonthlyAvg类的实现原理,解释其如何计算一个月内数据的平均值。详细说明该策略的月度时间窗口定义、月末边界处理和大规模数据聚合优化技术。提供配置示例和在财务指标监控中的应用案例,如月度销售额分析。讨论闰月、月末天数变化对计算结果的影响。","parent_id":"489baeb5-14c4-4d03-b73b-be142d956487","order":2,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/MonthlyAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/SparkMonthlyAvg.java","gmt_create":"2025-12-25T23:47:37+08:00","gmt_modified":"2025-12-26T08:16:45+08:00","raw_data":"WikiEncrypted:mXs39XqDeVdBrRJ+qhtod23hHIF+8ZsX4BQZDBzt/bJG1TaX82pems1CyLA/QJRVpc1gtR4rUE2Mz7jkFILVhTOz8Mquh2XvJSiS7tUV+sd69Ue7dy7syr/YJVT3tY5KdC4tVcZ+6AaQHoUKgpdkE7/NHqt62ofeLy99UlXNhB1Sr13tz7Z8cA8GZM2gLJaQgRjjtaWwRwXd+TXXH99iNX0y0IqxX3Z2NGYd9W5NxKWpm/lLIGQR7BrSWgUuR3GW5RGrM9G9DGSA4dzZFLA34fV6JwzzV9PbMdA4NJ1FfxgJDaU76ffikAiAZBhgd5JUzyxevE2EC2Sb5o64qdjbKDWE+zr768gvY63cYZmF/vgZEx/9/F2v5yG8Q9cZl0REsB0jM6PuLOSrCypGsGYffMnyKPX6VxL2ca/AIPnm4ALlasbMqhjELYeqeRSG34hy7O2NWjGfotC7plSLv8jewmaS48ID85hAiuS5kKC0vMA1xrnIgyg24POTaEfXiTTg/gTx8VP/meUK6dGPD0IuZvpYqV6YCcbVNJLs2oNciNKGeTs8gLtkRf2A4jBdQnf8W/t/VXBR4WIaDEDjI2IuvoErQVOsrQjrt0NozGrE8841uyoV6NXp5lDpYWp/Qm5Jw8jjI06E5xpsySvG9HG1EUwxIlvbd6GIpKx7CrryKg8HcdFQHIsFu6QKb1emr2lbtT3+v+ihty2Tg0J9UcGXSql4Iifyv8Sg6/gYh/UGQBfxsFGNYeu7Uj81wtje7PlZFEngYa0i+uL62RIFNubbWE70COrfgQkN0nXh8Lp5hD9PSBt5TaRc1upKjQw46RbgVKn6THM8y0WMWJPA6AGZIpcbqHLR78tBCZsHXQ1lJGVKujMDJAuSAt3HPb5oKzfk8yZQnK/xSN1giSKDVbBm6J49mCk6O1rJMojBOtOM+khEWX1PioJ905haDM99b4KbQ8lbQHe2OatpJOukUU9vfRKMiWVWmsNrAgdytoecGAnVtaUG0ImlzaVZEALhUsgpINQGggGR/DYo1wHtoSGEU+0QbdaANTlKnkl+lQ8s4HQrmZ+nVcZEHrpGh1XIQ/kLWyXOUzMoLuZ2zNn2HSXrjU1QZB/yJBRGoU9B6XJCJOXSdhiSAPY0MMpLnL8SQqqEAQvZ+7k/2T72QtmaLH6w9NJrZvqWGO5oaq5MCu9Q6TM=","layer_level":4},{"id":"68f6e22d-b8a3-4a52-90f3-e23d8a3f0f4a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"核心功能","description":"core-features","prompt":"开发核心功能文档,全面介绍DataVines提供的主要功能。详细描述数据目录、数据质量和数据画像三大核心功能模块。解释每个功能的业务价值、使用场景和技术实现。提供功能之间的关联和协同工作方式。为每个功能提供概念性解释和实际应用示例。涵盖功能配置、管理和监控的各个方面。确保文档既适合业务用户理解功能价值,也适合技术用户了解实现细节。","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java,datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-25T23:51:28+08:00","raw_data":"WikiEncrypted:luoNp8LvFa7zGThvIT9T4gfD6KbzJyTAydbcRfVv0b4BXBAF9G/unmbHb0x4cm5f5JJeO16NqGe5C5EiggSB7kaSbUE9o5eU3lrvtELMPLmmtPUD9vEFZKMT1fNiwYWUCr+EBC4H9HOuYwr0FYjbtKoKTYjnk/EbX7R9PqEM6JiTId8pOG7FtsA8Qf3iLro5Sql+Nv34Y1ew04QZ44ckNYPtXLFhVC+DshgqO2OIl5SP8jTVZswIrIaf/WkJ1RpWI/qF46LTLX4xJeO5v3KllbURfUIzthFkMf2LgeE1m4JJ9Ce/pY53MvKia7vEmkhGHl8NeFL9ToWbjWwx/+vQLWcctc8BxWeuhMHcNg42VlOU0WGiP3UhTiRr9b3LxdkeE17FLYKe7x3DrOMVtRg+yxkcIUgZ8/coGVjE8eycJwlyWdRxUDBPQY15YKoF0fqYtjOW/ydqYLhoqjDvYU+tpm6NwCfjw9WRBwbTgl567aWA8T0A1hJtVY+ptdZvdPmhnTJIoDunkTZqnLCixlPTca/EGZX8PD/D5ioB35ZmdjduAV99fzBSDcgON5Au/2EPjgcrCYDTgUUdEZpsCCLjXv/9q6DWrEYjgMg9TnaGApgkKhR5X4L8bxUlqiQix7fk6+JfTAPuZR5TkvAxblKuhxMfvdIOu9du/ZBv7uLGL7Wjtzs+uUxMuv4So0LyIPaF7Vnii0v242gm1pDOcdv89Tk84wWSYTlrv3RupYlkqdWidF+gmCXOaaOzUc4A2F4h+mmMd0RS4+fBafyBsYq0PVFwRCGDGkn6Ohzzdh/XgjyGZ0XdTnq6PeTZcFmMVz/oWPl7E+5fjSVfyjxHxr37FvBsrdgb8QllePTqoWmudcBDOKKhvrtgQlQYmefTW4bV8L+PJkBYq3aHm2A6hw0PCsoRztkDJxM9CQLYC3paUYQUxSda0szRpZUPU/YkzMrDbKGfFq5xdQVb9cT9dQ26Y0P1viWRdLUk1UD9ExH/J00+O7aGQNshZsenjruWPKmxkfgnL9pajGJ9axmmnUOQmpZnkFogVsgGx/fTlDDZ5l59u/YGFHPh0C9LB3Ks/Z+31f91C2ALpnbuEsFS4tEWeeK55kQJI8jOo8pIj+tlXiZNHuik5TXzVLdq+u1d15r+RRe741fIxGtFZRmAGoVsm0qNmHVj36794sS4Gcgn12JxVsrCkUNyqnowj9JtbbQM0jqZBfBGOvA4d8vwVUvoAMpddTF9r0kHC/NHSJhtNYPF7RQVi3p0jtMi+1advHFIRNs7jTpk/+q70y089+cVnJbcByvX7zXQvvJJ8EluxaM="},{"id":"5856ff4f-874a-4522-87cb-4ec444ac1aaa","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"调度机制","description":"scheduling-mechanism","prompt":"开发DataVines调度机制文档,详细描述基于Quartz的分布式调度系统。解释定时任务的创建、存储和触发流程。分析ScheduleJobInfo如何封装调度元数据,包括cron表达式、任务参数和执行策略。描述QuartzExecutors如何管理调度器实例和任务注册。说明分布式环境下的任务协调和故障转移机制。提供调度性能优化建议和常见问题排查指南。","parent_id":"401be447-6b3e-436c-8d7e-a0845a921e20","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/QuartzExecutors.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/runner/JobScheduler.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobScheduleServiceImpl.java","gmt_create":"2025-12-25T23:41:09+08:00","gmt_modified":"2025-12-26T00:24:10+08:00","raw_data":"WikiEncrypted:Ixm4kI/Z7v0V3JxitGlz9e2ct7VGdIoL/qkPCphPAVD0I0DArIeIHJXKfc7datZhK6sYYTP4NgavOprhAvCXiM4Ww2rCKCuMhEWZzWmelelIwHiRZAs+mCvDEWOQch/5EZk3g2W7VnKi6at/Cp5Yt1eAEsw50f8CDWVGLtv53fIyAPdX2DjtOc02txz0/gnc5KKCIQG8ajjV4GGmobRmqrz6pvkTT99oMsR7q+52EXuqeSx59bKwadHbhPP8H977L6D4qk5M5bYG3Ekr8l+ygi+kwngnesol6Pj3mpCAJu8YU3aC4L6kIP9ysrSxtNZ2LxlX9X8THWtpxkuWwMlou2PXzwzCFYTmqVM6Tlm0wEdgOxJG4a3BWSxpm40KpKe1/3IkVlGxEqEYeoZjGRsuRbeghFaemfqz9Z/Tl2RMoojiWZK64bqx36njOf4h38tmldUOFPpC8PS6AvefUSKeb+1PSVJyDnBkE0Wbk1KStpYsfe7xpNjvLGN+MLRsQbvWmXzBJ9joUvgwKo4z7uDEF3zeVxouDXEkHsEYkGUgEu+tcTMo1gd0/tEMU6+2OQsF1CT5P6ZAV8xZx35UZmrgLhQMmZDHRexy+O099IEqnwQ0kbVFqSycYEf53zatsZcgIma8sIFcP2ii334r05UdsascgYq2OoHCT86w2dS5BUHrdLUYfP9erL75QsmiYLU4taDxywLZs1nXcZp24xfxlqubczh5kET2YJ6FVvAfJDayoDMhVde5h71XXbVFAbNimpzDEBn9MJeF0Y14a4qsluduBGV0pYcpIsOCshGuoMSBJXaKU7G4zuyOefB6nkLPzjj0xE5vDtQB8oeh0RNdpHtginsHrXaEMUt13bp4aKpXvwr9pEdKnasg5XwxCfZnYfeOgBdcfJY3wlV3vyG483EZVpkEWh+gATSPpLV741MPZZcKpFCHrnxHUnZleIJnxRdWMQJcj1bZxDmvM/EK3hKMxiC6KX6jVTuTUkRq2x3w3kr+2de6Aa7GwZPehNd8lw8G3bCOPVTimhdI6ueK742B06YE3NVcC1pzO0GZ5Xojnei5eu8z5AD8GecM4PWGaPjqhZacaii0rmpfd8vmHYj9rYBvldWsFVNAzxjlz626hMREIR0kkUHfTZF6uyZIgrs6b0chl9kSe+hkQwxDdUl5C5VoggaAmJbG/ZMZ2IZjlrtE+nIn1fJMvVMWO/EYEuIRHlheVpo175JyRv+gGGr6K5x4yG5DFvaJL9wp/mVtHLv7M2KeJc3VdZn/WFGcgWr0sGp/2JaP3cbmXNtIrIyBOLDgUIfc52KIS+P9YeYkWorB4jzBtfOVT21tVeOaPBqfq/KGj9YrNqwlWPTe7OhScW/4SvWolpuUr0BoJjSGhAb4X8tS3Wfv+pnfJqbpRX97BzUgwW2zyET6N3J58g==","layer_level":1},{"id":"706d1a2a-8449-48d8-8a21-58483495929a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"datavines-metric模块","description":"metric-module","prompt":"开发datavines-metric模块的详细文档。阐述该模块作为质量度量核心的作用,包括27种内置检查规则、预期值计算、结果验证和度量配置等功能。详细解释单表列检查、跨表准确性检查和自定义SQL检查的实现原理。分析预期值策略(固定值、平均值、历史值等)的计算逻辑。提供自定义度量规则的开发指南和插件注册方式。包含度量性能优化和复杂场景下的使用示例。","parent_id":"c391a73d-20a9-4e3e-b13d-54fba38ef59d","order":3,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnNotNull.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/FixValue.java","gmt_create":"2025-12-25T23:41:22+08:00","gmt_modified":"2025-12-26T00:28:11+08:00","raw_data":"WikiEncrypted:wqMZoWM7JzuUrLNEmTF3PN2EChV5eJ6yN/Nr2ZjXK4B747mmEr+2wkFbHgS/6ttRjhELs/Sad9IrlwW6KvqLkCgxhhp7fUQphPEVesfrigKPk04I7xav06xlhzt7h2IbwSeubB71hSQkIOwX+DAWOyA3Qe+uPq3q3XiPDUp0pNPsP6ZR1y/mGNTSbh5I1ae9buw+nOEP5alVws8Pgw/LcGpPZ5YgjE7jRCTQgB/NypZ2YZ6Vt9FT2STqxyXpQIZ7EySnELkYB5W8PLlWvHPBuB9wJuWFnBeJVpEL2yPSjiCYzm35WY5Q35m/4vv3kTbkPjaBoND3/LHmVZvcfqulZx3CftCh65Zc2KAE85ydXOHJKp3k7q0GUSsTpkqbk+hIXiheBzklnXnLHwT9ZWPqfCU5TizSpw8dotPXytubO5BaM+4opY+BlVJCvj2tMju7Z83j08U+oGJ3lR0+HolwbYgLZq7IyP7moCHwMSCCzlbBb4Z5cNE0oaP9NoOXOoQVdRiyfNvkpv+iESQXIaHIsQYa/LNQdUKRTbyCgrql57PTrixbsUCn4L4rr5bDfAtdsAlpqZfTNWstOUrQq57vRfHN0QB/SpwGPTbn5Mqf27DB158W9DICkvG0LqNwPx+fUk4ooIjEv4biixWI5ZOQuISJMYAiqdOKcSSGGzXhyamDbra7mpK3nhnib5qIDZo8a3MIpLq2XS1iM8WT/bfgWkIlVCkhcF1Ejb4v7ReiiwIye9xXJSbl7KY+NuK3lkR5Q6sKikAkDOBlqb06iZsluAXIAnLQK7XptSN1ZIuOEnl8zroAwwgNBoQQGoDvsUCDAat2ikD8RDx4XJhnn9o86NgWonCkAp7BTrNWTW/ur2WURPRORV5QRdDXgTLcqIPESE01CzU5jd+43a0ULI8VPhX6RQBRIw5eRZ4UE9xo5N8ZGY+nHbsD3IvEPbH46cF8zZlaJYaTIMqmUVa4yX5gTJJ8ai0v+W96iI9s5R5XCybRugfR3EVcNuUOs7ogCSWtK52pv183E7rih0VCanZMi7tFxCVMAGUoVPhGrryJyR23vzHRIcsILBOzaMbLSuzNAyOGExbZ9eunXyKyd/h9iNzSEO2RNZ6/HTMAUALYCXqe55KYej9Ke2oAg3KYvx5+gDiWioxOuf1VYRn9pQN74wjngRw1ypb2mAXst1a1z65s72Q8dWgRIBDzzHlI8S6EsDzD4WHx7zsbCJ8HTrDVKw5lQXRXWyJa+hFARRGgL4a8zwpDArTlzju+w9Ur0t9+bSNbz5PRbcDLt0J2Z/XZWfikMuXAnb0wpeXoNAQ3DfJQyMdBdwB/t7PkIF6epggaQjXf1g+iKzamuHg3afWErqOkB9W0fHdgO+mbxXSSbbaxCIu7/FXvbcPgWqAJdQe3LnU1RoUcjyc3ODiDw0cPwWVkYvSYwaT+CwH3DTyCZoG5FKwlLKN6K/BtcC6UxBGy/Npq5ga9iPgQeeWaU7InNnL1ekQSke1U9HJ0h+Crls28xgLuJApC/gN2XN13At5P","layer_level":1},{"id":"79be2698-1734-4be6-a531-b8b79079f7d0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"告警通道插件开发","description":"notification-plugin","prompt":"开发告警通道插件开发指南,详细介绍如何为DataVines开发新的告警通知插件。解释SlasHandlerPlugin接口的设计和实现方法。提供钉钉、邮件、飞书和企业微信插件的实现示例,展示如何构建通知消息、处理认证和发送请求。涵盖通知模板的配置和动态内容填充。指导开发者如何处理发送失败的重试机制和错误日志记录。包含安全性考虑,如凭证管理和传输加密。","parent_id":"f7482163-91b0-43ed-b702-cebf50029b91","order":3,"progress_status":"completed","dependent_files":"datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java,datavines-notification/datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java,datavines-notification/datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java,datavines-notification/datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java,datavines-notification/datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java","gmt_create":"2025-12-25T23:41:31+08:00","gmt_modified":"2025-12-26T00:25:54+08:00","raw_data":"WikiEncrypted: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","layer_level":1},{"id":"7a96921f-9ee4-41b0-b41f-58237a7d7538","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"用户API","description":"user-api","prompt":"创建用户API的详细文档,全面记录与用户账户管理相关的所有RESTful接口。详细描述用户注册、登录、登出、密码重置、个人信息更新等API端点。文档化认证机制,包括JWT token的生成、验证和刷新流程。解释权限控制模型,包括用户角色、工作空间权限和资源访问控制。提供安全最佳实践,如密码加密、会话管理和防止常见安全漏洞的措施。包含用户状态管理和多因素认证(如果支持)的API说明。","parent_id":"b4082be3-2f3e-42dd-89fa-9295da3c62a6","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java,datavines-server/src/main/java/io/datavines/server/api/dto/user/UserLogin.java,datavines-server/src/main/java/io/datavines/server/api/dto/user/UserRegister.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/UserVO.java","gmt_create":"2025-12-25T23:41:32+08:00","gmt_modified":"2025-12-26T00:25:59+08:00","raw_data":"WikiEncrypted:SmmNTSq96N8aZksVSKE+80Gk2G5wakNDcR9kcXcf/ufSt5s58wAWPPkXSMc2g1AijP/QfhMGfK5A1BjHbPRTgPFof1kZ+mWOLo4qmZDf7t1zGMj90CVtVksgUwMYYpZxWJVWpyluZtpVykMKnNUfRJvPHdfh/APapQ9NT4AvaXoeTQo8A6gB9E/TVY6+21B8VkY9B7qe7AWV5fAnz/blcRgX3yOe+ELkourEIHadrjFHfoA57NTttthTwl+luRk+armY8iHKAP5WYfBumkWqtRBe1LGkrjizN8RIXxfPXPz+rPVd7tm8ho9BBTdySl4xUKev5iaFR5rqeZfu97v38BzovuX+XrxoAmbgQZ4DgWjtL/hNyBWoFfIaIhlpQKeVo562LFIwAlRLiOrh5JpPrLrRfNQCBBt5gNoviCBYAlu3nXHyYUr6tnbG+9mewWhB8MC5H5XJN9PLIizroYGnYG8RBc+BTyUqFroTG7r8L5d0K99+dHrYGMDy1OwlJ1xXR7UmLzkWDCU88WdWFTaAD6N+jl6WQJY5v8+dA9NkqGoQ6+IWj1tEk3OVROA1PhIf0nrc8jqJE8zlK0HM/YaagHaojClwg0/76YTq45x0BSIqHuvxxgiIwe+B+JvTXCq0G0xgd4lTwB0K2vnxZ+eBI5OaVBZFcKpL6TRUbgAi7OOJdlSMfPP8GwggjzNf3dmk039rzrxKGBfPUNjK6iArT3L3UGYwWHdc1vMCIIatbFQw0nGXp3zzcsRSpmQf4Cge8gDkTadu8AMpz7E1EZavkEMEE26GWGLAAYequ0Sm2Hg3brbkZ3LXqCa70CB/+MtfSvJ0P00DeSoKb0mze7ttmLOi9+uTxitJ9cmGPwr6nuWBTQgz9OuyFYUMBv9//Y4T5GhvvBfJ16EgI99snzIIURnmnKQAI4bb5rQA5/U8/Ks/IOJOt/InBvC/2/mcdp9xnUlpfAg2RQK6RA3TUVS4Z3mvJjwyVmjg3PNOoYtRTHOxKMl7qK8KKPLFjG2VGHTJ2+eKUOcmAtZ5sDm9eRf4nsdzfy+XrP5BbqtTuLYJfkYKHksioAt8fT/h7c9xa80cPC9fSC1k2oXZHqJC30fk4PLnEYnx8GuDSYMEoo8VLA8KqopA6U3UMX9G8FKt8CzwpV0tbim+CdrE3AwdJ88/cOPcSS1Gp5vOTBI+kORsz4jIfmcoZRKFp7xWTVVGhRwkF+rRumGEi7OmA+ylftHZW6fXu1+1yOMg60Nu2akOJBUd52npk+EyHEA/2OHb7TWkCA5K/vnsQDyvRv26qsz19db2ymK7KNT4RUuz+/u2PvEv8444Exy6WtjpMzRVytSuqx7VASvPlI/iGfllrTKHmFVEyzGpCT+ilVuYD5TZjy02r/o72gNlIhv/hXGB9WCjAIYt2A1d+AWnA6SM7N+Zq9nM0phk1rOSEwCOQojcMQG1CWjDPbPoHWJnhe4Eri3jKvKop1gRPNTMIUxAdJk6mw==","layer_level":1},{"id":"e9d40891-b388-44f5-9b68-9a7b7b22c064","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Kubernetes部署","description":"kubernetes-deployment","prompt":"开发Kubernetes部署指南,详细介绍如何在K8s集群中部署DataVines。详细解析datavines.yaml文件中的Deployment、Service、ConfigMap和Secret等资源定义。说明如何通过ConfigMap管理application.yaml配置,通过Secret管理敏感信息。提供Pod配置、资源请求与限制、就绪和存活探针的设置方法。包含持久化存储配置、服务暴露方式(NodePort/LoadBalancer/Ingress)和水平扩展策略。为运维人员提供生产环境高可用部署的最佳实践。","parent_id":"a5e4da90-df85-444b-85e1-80088657b90e","order":3,"progress_status":"completed","dependent_files":"deploy/k8s/datavines.yaml,deploy/docker/Dockerfile,datavines-server/src/main/resources/application.yaml","gmt_create":"2025-12-25T23:41:37+08:00","gmt_modified":"2025-12-26T00:27:03+08:00","raw_data":"WikiEncrypted:sraXPYr/jDM6EQJH4c/QVUW2Yk/N5Nzc3NxcxMh381UG2lW2CSGa0MIRX756KZLlkWf3ny33HHMy9cy7cyopMrDBATpRyEktU1fbslVJr9W6MwZznjF5J3AIXz2WCOKAHESQfY/V3K32OtcnlF+Y8YqCQAXJ6f9g5HWPC3NdrJFNxPd3RrscsqwPzPK9lcBgxzFVbdLsZG/7ZFhDKJ+Zve4UUeOEszxhRzK5dI+bmeuLuOSe8Mony6sXJHZ3n3GrTdXwu0JSyg7F3D/G6qKHK0usVYP3QoiHWOQ/oovC0f8jRDmg+PIl+pzcsGZgBy0QuptB6RTi2Qd7lzWY6xNh7xN2iaCRXTjdWoiE7VePc0YIiwI5CLULneOKLN5NyyTcT8rwWo4oXqtvcMTWmCHBLlYqfpQRhDChcYBXELG03ay6RDlXHkktV8O46L7juGF2ALLUbWaKHFjWcm1vVoIwCOwSVzeChk35VaNB2Kun5IR2rgFRiYGsSHTNdGwQYtzohRfh4ngmQmdQ7pI7IGZ0QYHW2WNr7gsuqZKFx67efCDF2Am0NlOLJVMnC+3pK+4qxn6tjcUfFWy7meOc9wtMFCWOoAOSwEyI/ymdMboOCNK6mSJekEvg/KWxZd2k5Pm1PX8JMmWIDjCa3vvpRf2bfQ8bgZV26Nkb1d1V3GDR0Y5jo9enZi17fFaWouc2ISIOQ+pJKyZFLWWgmlSUWh8aydDo7o4YcbEFgOiVnF4T7Ll2W7XtA8wckFK5XF5EJ5NKQmjIyRblfyoygATCKaBywUXb/MM9/SJlM6qkaIxsHNACPR9x+8dLbth2+rVsZHpVbsaAdVqDitTluNaN9tONmBrkBNqeG4DGhe3voA0zAn4BPGfBRGgskWA0pmGG/T/D+c7pgH19fq0FJ8T/wsHY/75lEmdtByYFFvkTzpNqnl11r3MEpSKI/rNJXST095UTdlfQBoRn58knOCt3M1Da5y/F5i2CMezMJ90H8X6zeg6XwMIMkcb5cCMQomOX2Sv+wl7VIw5DzMiuWaV2/PikyxTMfljr8KaMKJ1l5j0Q8cJ7XB7liMIxQNXHKMEftjiGm9IUL2wcDoyu4ZWk/yS7wHyC7aFtRM7CcIo4v24C2GZuufOXp22d3H/Vm+DuVRmjS1c/wAiWBjZEJY55kC7/rQ==","layer_level":1},{"id":"63699421-4dd9-4fa5-9009-18651ca04007","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"性能优化","description":"performance-optimization","prompt":"创建数据库性能优化指南。分析DataVines中常见的数据库瓶颈,如任务执行记录查询、大规模数据源管理等场景。提供具体的SQL查询优化建议,包括查询重写、连接优化和子查询优化。文档化数据库配置调优参数,如连接池大小、查询缓存等。提供分库分表策略建议,针对大规模部署场景。包含监控数据库性能的关键指标和工具建议。为数据库管理员提供定期维护任务清单,如统计信息更新、碎片整理等。","parent_id":"1a586877-260a-4728-a2fa-ba930f91fad6","order":3,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/resources/mapper/DataSourceMapper.xml,datavines-server/src/main/resources/mapper/JobExecutionMapper.xml","gmt_create":"2025-12-25T23:41:51+08:00","gmt_modified":"2025-12-26T00:27:57+08:00","raw_data":"WikiEncrypted:9uOBpMbLX4DyZqW4us3Wm3Q7klXxmeD+JMMoGiSO2oNryWBo1gw9kLkawvxQIW9CASZSiyAjiA/zeT5DwD4S8LdDaHdDTSSdIgWPrRiVZaLyWJgPb2cBjqYS9rfQJtK6x5h0LZn4aMJrsuUfwy5Mp2y5sBe2SzxR2ucPQekIg9L+wGkP/roxZJiBCxkIp2zNCkcR8e46ZjBPw8mqa28oMxmTFmpAWJxXqg3cRaPpbD0LfkTeSifx72hkrecjOv4PxWrtXaSbWVLEz55E4NrgYziuZk7/hZyel9pusoNZn7EIksiVsrFlbpLMlNX3UNUycyy4IxpAIkzIJlToogTT9HJkcrEo88P3DUC3t11vBYnKtH72vnXXYGw7feiJPSQyyk2iYe22NOVV1hXozsbPEDGcOa1tF6kj0kPJcKM6GQO9R/yp8a8cPNPQ0h2afDJicCzusxIWniM8jrGM7Hv1sV7Kmkc+z5/vRyKnZ9zkmPSIMLQEHsPmb6QvPJmJWOdEGULAMa7STCiAf6b9IuNSldwbKpfijmHDVzPKQ5fMATWUsmD25cH4C1s65aVYYI98ofOI75qpdYGmHufrm3QxPsg6jd8zj4D3CnWhrk5MLNur6goAnuc5JxYr98zs82iPF8Q4x/GRaa73URAAUV30iGXS6Myj4NVDqE+ODVwazgkGBJ1z+evvRp2qpySd5MhnuMK0iGiHk7mQpXQ9vHzbAOlHGxr7gax8eaRoKFW0E3O1t1BL0Z7oqhLmLC2UPrJBbznElINAeLt21uY9Kqu7Y2mch3IkP/rzUeG50QJGwxwxmlM9hz9Bs5BEqBfiyhbZiwrfVYVF3EuD/LKGR89G7essDAYK4/h1cybxV1EmaHw3Z9ROs8XED+QKS5/ARf35U2cPZZjID7NolZIOBYrPSzbcuo/y94kK/69yNcZoezZkyDS4d1JFir6KQv4SG1FFyp13k5EYBTXQl1YSHUfwC6yJ7o37y0eAepmMEzF2G99qe7oPe2FpSMnIAuhXCI07mlYyd+rPNys89VrsBQVc0PYNjsWgrEkwr80rAg+zHMOcSHQha4etZGXthkr9S06b0dkwYs79zWUp0r51lI+Xirt8mzW3TBaFxObZknORq+89juhxjRbt1cYAJfxxIMNMmvrTDKs0qXbT4sy/HQ9nJzipv/QXjschdZkl0vYBGP7OOS73GGmev4Yq4461VYv/VYxbl6FakjkyFue72z5lYW5+ppnGGHfc/rbDz5Iag0A=","layer_level":1},{"id":"8938d0ac-a871-4818-9b4d-dcba6e588233","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"通知配置","description":"notification-configuration","prompt":"创建通知配置文档,详细说明DataVines支持的各种通知渠道(如钉钉、邮件、飞书、企业微信)的配置方法。包括通知渠道的启用/禁用、认证信息配置、消息模板定制、通知频率控制等。解释如何配置SLA告警规则和通知策略。提供通知系统的可靠性保障措施,如重试机制、失败告警等。说明如何集成自定义通知渠道,以及如何通过API发送通知。","parent_id":"5d2798df-80b4-4ceb-b66b-9167054fa556","order":3,"progress_status":"completed","dependent_files":"datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java,datavines-notification-plugins/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java,datavines-notification-plugins/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java,datavines-notification-plugins/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java","gmt_create":"2025-12-25T23:42:01+08:00","gmt_modified":"2025-12-26T00:28:09+08:00","raw_data":"WikiEncrypted:4+tXcquKioWk6hL5AaAVve4atpuiCMPXwRL6MoD2hgKZqQsC4e3Ck+xIN6ICvCR7ww1T8o0RaPpPHQVzs0Rb2cliY+Wncc50cg5xUVz/Z7c7+hX7MoZRdoz7jpluVu+/2uSVA90MvOOu2Wl7a2pfCpOsGPZoQYjuBa25tCy/VqWm/z2EPXZow3bDZkdUJmtnzQGT7atC8ptvwka+wcKyRvPizCiWOePWjzJ/lPm/9UDmv8PlwvSQr/vtf/GFqt8GKhHXGaYUmE8wMJ4lRIxBYzpw+FFrVzd5v0odvKi8Q0m5g0a+p8ilL96pwyzNKS18+Z5WgMMD/DHiXE/awxk/bFQY6/3KSgCx5UT9L2voFJnbxwyWRR7KOG83C/5kJjeC/Zut/bu1MldxHnDIhe6dF7Ee5kytGWL7XSb84+fCj7o7JcJXQ39wxiTzCC0vVqVfPkfmNnmrXlF6G2aWCfcq0dpSnTLzV8fKrYLTnc+q1CkeV/Lg5He1DjYbxs2xnTZp6iWaEFGwF5oOquxN7fi+35pvjdO1OkX3z6XHlb1Svq7zXas5yTTFgFNKS1ZCviNGMkWoUd20Ya4F7E4DER7PkCyzkmRTcKCyZmM0vRUC5SI6LKnbelAzPtbfR8jzkSWiJyJ+0JRpPtmYYCNLYYN2HVJ3RXcuqYVu6mxEmwhp59BUbAERZWm9sAe1WhL5LivHGCGpjRuhp9N2z3nN0PBLuGfqSJSMN4JF5iytLBnoSR0z5hQ6vleJbzosf4t/XEUvOMjuzXeXe61XrO7Okqxj48wcFKfH7Lqd9DUMaCBk5cGBYqL9bBoFyXbRVZ468Sh6yH6cdHswAxXHFg3w9B6oAqyzkvJS2ZtVIWH2xW+W9tMMipkIUxX5kfe7ldUhPH7SqDTmLvIyoVBGQ4aOAz5rzaQRrCGn/f/vLGkYFt8JuRgi7Y47yc1gAyu4qN0logYkglccxWW3AnSCkInUBZxwAbNSMb1QB7dt8Lb0c7JGApyp0fckQOiflEPl7PF2+5citSIVWqhTyWXjuWfM9XL+zn23T7PheUtnkI04Q3d+is3MjgBGr9ywJm6k7udZtrZE2/xC4f+nHes9LsKIIPsM2FrAoYf8AijoR5cTRq795tKYXF5GqnwNOBzKulCxinQwtYriOXLbt8M9H7rY4bKU5vea2kP+gdbLsJqLmTyz7KV4GJkka8atd2N8Vo37LOaaO9vuax2/zlA4l082GjdFTux0B8Zn9YfIkbtDLtkCnwMRMaAVg4O8yafnDdUidIf+lUWa59IjOArTmaKa7LWVWBKuCIeaWE/uXGnSOHPprVqXcHz5I/qLuJxkAqv4y3VzHD9NhXVtOqTdtUlY1hWQZi5Z3qlXVflvKL8kaHcMDZuKBbfrqmYW3T7SPxDXcZq5HPA6xTyR/B/KFyDuFu6vx/yTPeYGdjQZRKMxFcZ/RpnxT/Oj6sdg/OOcBZFuT6gx3J7C7YQMsxYsKHpbxC7ruSC9hXPgNfbyA4je1WqYGxONQKxdOkmaFw7AJOOE8K4iCm77L1NOfdcZMQt01PzxoJTv3m0i22nIz4RytjV5gmeSfGetJA3pqn0CWNg/UdLFtzGbj8+Wxo8InWPhWdVnrnBL9jxhZYkB8XaxawFs7q3EeNaj2JPmVQs9TyT0MguzaP7oYUq6m8+fPtVtCQwuhLG1NTYlSudOR5BCv6uNGSkwbvFkMc1u4PbKcEF6MaEg","layer_level":1},{"id":"a2152a18-ea14-4a41-80d9-cc7645d5b0c9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"调度策略","description":"data-quality-scheduling","prompt":"开发数据质量调度策略文档,全面介绍质量检查任务的调度机制。详细说明基于Quartz的调度框架实现原理和配置方式。解释三种调度类型(一次性、固定频率、Cron表达式)的特点和使用场景。提供Cron表达式语法详解和常见调度模式示例(如每小时、每天凌晨、每周一等)。描述调度任务的生命周期管理,包括创建、启动、暂停、恢复和删除操作。说明调度过程中的依赖管理、优先级设置和资源竞争处理机制。解释如何配置调度超时策略和失败重试策略。提供调度性能优化建议,如如何避免调度风暴、如何实现调度任务的负载均衡等。涵盖分布式环境下的调度一致性保证和故障恢复机制。","parent_id":"a19e7b20-774f-4c69-a930-24d3fbcd2f0a","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java,datavines-server/src/main/java/io/datavines/server/repository/entity/JobSchedule.java,datavines-server/src/main/java/io/datavines/server/api/controller/JobScheduleController.java,datavines-server/src/main/java/io/datavines/server/enums/JobScheduleType.java","gmt_create":"2025-12-25T23:42:18+08:00","gmt_modified":"2025-12-26T01:16:01+08:00","raw_data":"WikiEncrypted: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","layer_level":2},{"id":"749e3852-d9e1-4440-ae18-a69d01ab8dbe","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"结果验证","description":"result-verification","prompt":"开发DataVines结果验证文档,详细描述任务执行结果的验证机制。解释JobResultValidator如何协调各个验证器完成结果校验,分析MetricValidator接口的设计和实现。说明ProcessResult如何封装执行结果和错误信息。描述验证失败的处理流程和告警触发机制。提供结果验证的流程图和典型错误案例。讨论验证性能优化和大规模结果处理策略。","parent_id":"4e0ed203-0047-4f0e-b2d9-d7fa1cf34621","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/validator/JobResultValidator.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/MetricValidator.java,datavines-common/src/main/java/io/datavines/common/entity/ProcessResult.java","gmt_create":"2025-12-25T23:42:30+08:00","gmt_modified":"2025-12-26T01:17:20+08:00","raw_data":"WikiEncrypted:Epdytsif0BKqv6RSnKUYh8ebD1jSEAoZ3xv2mU4kt0HXD59WcAdeDr/N7I2k2oONK7MUrEAQSLc+Ee+2zv4OJfk3Ix2OrRfcNEFLPqn00rtY7jlfIlMnSonS7Z5eFE8jJ14C3wX+7ErpRkbNjNK1qN/lwrGwqqM7whjT5eCznPCUME6QEvyVS14M5n3Pnj+E1gvbOpTls3TKGI/KNI0OnKRVUqQLSxTT7Gc1KPkdG8/6EjPsnyx5PxEWtiz0Ksfpd5vxxVKy0Lw5HJpSJJOy/xVXlvCZLAXuiAdT/oGFlN1Tmqp71e7+IUrrQXEpiWApa8JWVfOWdCdqiYKUA5PwVwQ3KHVWFuf6+3guVLWyP0uQbmy0sX7DZhSx8fhc6wtCibZbeXM7S5WCpUwgSOGJMEQCYwkK55XY2zfXFGnYuNNCDoBTLfJWCJZbXw8+jjeiJDZL1dtuZbCtv3i6SaHtk3O+c/qtWM+K/n7qVDCR0iMRpNG8Ay4wLvSsKmc8PmacUvUSVZYuGIbZWqi50cZGY9G+cdLWT0pK9N3ZlZcCnzx2jFrBOBrij7EHh8r7cO5EiDYLnCwouDfTkRQFF8TpATRKmGOQBzGhbdKnb45cj2s869gsw39lsJQ+p3Asv09/qNPuypJEcZhydVpjq2fmvXafZFCP4ceDqLtoENkN8nI9AazLezGPEjtzmIm7qmvjnoNC49o7h0OJyAb/zm5dx4XmXOaqwY5l0CNiS6cwdZI1OBRg/UTDRmsQPzbnWpIFS8ENHGJtr+Bt7WXxUxioaq8au7horDFG6jDMdJcTUkdIziUIIDR2cBC25CcUuXp2MaVHB0ISymKJlFwbg9tXiFjbvaY+7IYG6jurRakOGcTxqpRIaRxPkbG96IPAT+M8NGwukYPNzTZiMAhCvWqGsKZBzsj8cXrEMUX7T7MsTnRTM3fSrlB90lAID0DQyC9TFr4rF7Gb4lsnqOOYSl/77eEknilBUlqY1tBboo5pyfOK8kgJvdGs8dgoGHDKLiWlPzB7J7Az9b3R2ZSIBAF7ezfbzYMgnVLdkNZySMdRzeHtdXM7I936F+KFPg4/q/dmwpxmGnQWt9+nMk6EG/FmYyxBipZ8xtpGvuBjUuYTvTddmZ3oKt4O+LSG8MyuBBDJB8C3VRhvH2ANHfX0OoR0sG7YQ0fQuEVd0UKvphFu5jOY9eYCkD6Zi81p6Jv2kASqPyFJzEVptYqpktWDM4b99Fd5DHiv8qwGCZuEdP2/O4I=","layer_level":2},{"id":"d6c19b9b-50fa-4271-98d9-b3558ca0cc04","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"客户端管理","description":"client-management","prompt":"创建DataVines注册中心客户端管理文档,详细描述RegistryHolder如何统一管理注册中心客户端实例。解释Register注解的使用方式和自动注册机制。分析客户端初始化、连接管理和资源释放的生命周期。说明多注册中心配置的支持策略。提供客户端配置参数说明和连接池管理建议。","parent_id":"da4c595f-1508-456b-b54f-fd0b5324fa43","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java,datavines-server/src/main/java/io/datavines/server/registry/Register.java","gmt_create":"2025-12-25T23:42:58+08:00","gmt_modified":"2025-12-26T01:16:52+08:00","raw_data":"WikiEncrypted:kSMJmF88qRkP2ukfVdKPFMJvuQJsyPi8pR1i+fIkvJund6vBC7isbod9+5euH0o9OE3hZqy6kyiVXM+gaRHOmNNrIrp233WopgQrnIovbfK7Mba0F/krRDsZpw86+JQgJwtkyKOt1Pb3JbJaklSX+lCx+6uJQZvCEPVLusc93/AT/x8VPQyGKRZmskP/XtYdJ8fp8XXJyDEyiZwhIRVZ6MLUaJwGYtM0he4KnogD223dVLj7rXCLk8OaBxy0ZhVxvTNK5jwOvDKN47V5TCxmLDDrGICqkQK+9V2PDD9t7gjzFIQv29J5wjzrYIwBNZQIZ6cy1q0yvUqYWU6PMM4cfTfhUvWqMUSbzskeDqt7IGxlTEa6FAWYHEIbqMSMmbGf6CIK+gnBn51pbw01nHbJx/zL1yIzw55dlMhMVCC72CMTnKV1EPw7Rm1HKf0VkgB2IJPa4StnukQp+oFPBYCi9Wi2yXA2o3h4FYvklKwpfxMBH0S2DqZGbGQWqgvlkPnPD8lOxVXkIXuae5Djt/BJu536s5NRS/uGe5K+Q1sd0HxU1jFXMv8+tPEzCxn4VNrr0PRqa8RmYxm0ZRGjYn5aBSYmwceRVyh0AWKxeUSuOhZ0pFRDXz5WcxHaVz4orNPMlbidwNdJSLjlxIaXpaa+kDGHiY6lzUZOPcKNAkFmdMeOISqpXmtOpl0kJXHTVeW+n2/ITlXgnAnIT5jN4BOBZv2lb7tQK2HffpDxdfwUAd+cX3qCz5pi1aDpvWvTcR+nG8xHpcUZVxZkpT+2RhBoadQt/VnjfIkQxr7ILY63i/WxCEHbTtFfDb10QFZP5qxl76VtbX6XQ/VO7mBaU2Huvxw1cVnE//i3gdOcxqO2ru/SLzQMCEUks78qsVv+0bfAj0UlmATY1sfx3GsqsQVNJlZlorjsk1cdrHFFGwGsXt2A9+5+8wVk5PpfCHfGHONS","layer_level":2},{"id":"bbd65494-8a17-4b10-9e78-b360cb044f38","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据质量协调","description":"server-dqc","prompt":"创建datavines-server模块的数据质量协调文档。详细描述DQC(Data Quality Control)子系统的架构和工作流程,包括任务参数构建器(ParameterBuilder)的工厂模式实现。解释基于Quartz的调度机制,如何创建和管理定时任务。说明命令模式在任务执行协调中的应用,包括命令的生成、发送和响应处理。阐述任务执行失败的容错机制(failover)和日志服务。描述JobRunner如何协调任务的执行生命周期。提供调度性能调优和高并发场景下的稳定性保障建议。","parent_id":"6f063aa0-15d9-4271-80a9-edc58df4f3ac","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/builder/JobExecutionParameterBuilderFactory.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/DataQualityScheduleJob.java,datavines-server/src/main/java/io/datavines/server/dqc/command/JobExecuteResponseCommand.java,datavines-server/src/main/java/io/datavines/server/dqc/executor/runner/JobRunner.java","gmt_create":"2025-12-25T23:43:03+08:00","gmt_modified":"2025-12-26T01:18:26+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjMBw0JVih13om8lNoD9xVHHXsqW/J+g3sSHQxZM8eixJ0KAjRJgth2nwbA7S+E3f2nvJiTkbp0sjR7hfOGY0PWo8X3j496GdfFUYNLKwzyPnDe3mzpL0cM4WWx5c2MJEBxDme6cpYcSiQ+2BFOUiqd7E/X/M5Pb22uguCfHTKVkTNQ0lvK3Az56q5c56n2Ho+OEG+oLHYFEj2n9Ru558p+sob272rp8Jr9rBHDZUr6gPB6wtcRQfF/RW0drFQJ3Zh+0O/V+Mv0umdTO5XRwiL7Hu1wt627VlUDwkGrYqeRlWnXz+NiamEhdHsbGqzJ7gzdDVzncQdAHjawOfk5ES5haPevwLdkOBBvAdhmX0+KqI7r/Kh5iX45uLWECc/HklQDZEdFZDQg5iVdVGA/KNFihMXoYhoreQ3owhwdiswh5CThWeHYPXwVj6HIaggHJVVVdtosKrvtCxmZoehOBn/G5eQaaLaS532DoU4+Y+AQRYLlFQs0Nq62AJDlgrSPFRHeSnqS8rMg7oFco33Yrrvg8Z+QtdiqPJhJHlK31KfD7rN6HuweYPTrJ1xsTftx4TengnPIYvRH41d2l5XNWTU8x+ibf/W9ZUHlHpJI9AC1GEKSASE9LQAAraMcnen2uIA+NW7VoVgTlGQC6/vmBWugcjdI7PV/59PlZoPLoqc64ojSiSvYCONr19eHOUz/U2uXBNWjC5RjkbeKSgf+uP57Lst07JKD5ZJLWIlnJluEXY1LHwgthFF/pVmDat7FkxWFMH2ittsb9x7CEPgF3s3Efq2JNk0OZGvYIqoD6Vg4wMozMpOuMbLEl4EUNzm+ik3avSMZTXWw7tSygEQTr0VMtqpQYuK6zyQ+h3ycI9N8rYhM3p0WUWXOSR9iANT9a9ZKOm6TfwglFVM8A1AiSkkm6tRV7rgtYUenEhnW+fvCqt/dTsnEcRGBdT2y503IzYWADy5AFU1Z2bXxXpLqQfnrr4AV+Kz/yf5MzTbwvnyotDcVJwYU4BHtDqIVxlompajul57Q5vBNBss/9H8gubuFawwsNK0qLO3klZo697FgYWcSguNKOukuCmi2D6OyYiWAiVaPhMUGvGFf05Cfr/Z03BApYP+WiwUKn0/JDn1dq/ig5SS7v8pHpwFRoXFUdIVKsjuB49ixtRol2l9t18Kc5qoWv9bCXhJqN8Lrj9/S62ETNYKSa8IeaeJgwV4u0UG5GMYHnTCr3tTvFQTJqg7GVVUOrVI8aaa+1/yWcxBWcOLiDf7/SYxcNohKzhV/BKWWg9uFb+/AZKADfP8ROZoa8SBifwzL8KkTtle1C4R1sK1pN0dB//fR72HlusfnNuNFomxxlOCvJhWLoNm574gFh+EoX8wZiHqjk/RDQ2DSBupHRQXT4F0LPRcjemSLRRQ69LUF8iCqpD4iZ/MhSLKT5M0oFYaPeVQ5iEA/WllTdKzBYMuDCn2H0nhvNRRwT+jpa8nwLHSGWt2El1Blav2zxn/0MRmPU+kdaFuW4VzyYub5HhARMvYlIIoHO+XnBW/1lhLpWqFL82wb6mxZofuaDzm9CrWGUCkhitEyiQi9HF82avcNSjFK+5jX8cGr5+Qw==","layer_level":2},{"id":"07b63f3a-0384-4d83-9231-bdcd684fc464","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行器实现","description":"engine-executor","prompt":"开发执行器实现的详细文档。深入分析AbstractEngineExecutor作为所有执行器的基类,其任务调度、资源管理和状态监控的实现机制。对比AbstractLivyEngineExecutor和AbstractYarnEngineExecutor在资源调度上的差异。阐述BaseCommandProcess如何封装底层命令执行逻辑。提供执行器与服务器模块的通信协议细节和性能优化策略。","parent_id":"bdbc7ff1-6561-4953-bfe0-96e43c8b3e3b","order":3,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractEngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractLivyEngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/AbstractYarnEngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/executor/BaseCommandProcess.java","gmt_create":"2025-12-25T23:43:15+08:00","gmt_modified":"2025-12-26T01:18:23+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJ0m3CIz+jQemkgQbfXfNl2oZtPYoOOrDe1FG+r8ZhUTaUBppg1whjJQN+pidbjLd7dCqAD4pS0OZlh3qshD44gACmiLiRlMXLAusDauA3+4Djaf+LCtmQotAI6RDtxXH2t6yaxlOlr4fUc8PBUdPLyxv0j9n8y/NrRrc/JWIPHJ+mk2hWRWRMhuRemMD8LXqE7QMZFoRqLuy3To/O6rJA3d6XI9IHX0xUE6m913leMEGMagAHDxhw87l53BJW6c15vD/mXncXoHTheTmfHHLQjCvHWUImVT/AGwsUslFNFnddoARWOkslRNbkBwH94mtac3zvYGz+KG2G9wmEoDHRKPOq2ensck0Cc5zvTq1DAfYlXfsOsS043toB50EzamDzDhTL/CIjQ1jowNJYBiWzi8waF4Lseqyz+vFzeXJ8fv5JyE0IFTIBkx5PgURmXexOY9B2H/NC7baSvrUDzl30nc/SVEtHf45OXyYdQBv4JLtljnTeSW8xnCviTcl5+/bTcITTEL8PcQST0gqQOSxGnK55TNpDB4p6i3OQMPjz2rWF9TzST4vHQG2T+NuIPgece96ZyN24zir8oOXf+v1y9ZLUph/sClnKYZHnbZSmlgU0ocgP8On/TZ5cVkstE+JctqVxCED7sGl3QUYMjhoxLxNbBM2TAedlSHK6Kvw7MgnDhrqwS/ZODAzf7ZwdSMm97MufLYlDmQjU9YKQi3n34KKccLBfFehuU98X0A4i2j0jCs6pDNotsFpYAJB26KFNWVRHxTbIkjnOurYvJkkEk/e1hPP6pYw1z6arz56F9HwC+Tb3inbyLqJFGb491WDe4yPnCF/0Wkv7ENKyKCMA/gioYlSO4wkbjrRp9F6Mf/ICvrzjQatmoCAg5ygY/WTMxAmpaM8t7ZUotEMIuFaWVU6GEhu5zH32bYCMRAzTqrNK4PtuQuYGEtl75psuURfRnb1K104zdQVS3HrDrFoY6Ko3F5t2iJJoWwEda+g3gMF593gbxRV1zwDWyBdy2VW1O/7Kqso+rlmxEsw5AdnQhN790aAimvCNQQWeB9OjCm4BTOTGnyGh1DyJRsShUGIMSs7rTanEpDa4dUlKFtS39VvVfo0BQifa8eTXboqc26xDPnpC9ZAygQf1NtelRnOx/3oI7JBGESZumgnrH2Li0ll+xncIyrU+Orh2HwAg8ha5emt73rZhhrbxBX/F7w9HSnoJEIiimJNiVRr2Z4LsZjfJYFnLrN7jnmOAIJ0fYGfggeG5ZhBaGgE78gu6hK6OH1dyUQua3t6FaCoT6ZAFYJRtQMLLjNbojwP2pn5xHgFgtKuX4qzL5R4FDZymHegYdhR6LfbgbwLwkuHw6Krc0O0PYv22YZ6tVQqEgfQ1piNOXj73JffeLuKlpnmT6y+vvZZZYQox22Ma0GbK8DFODUaWPYi0+m8a0umGXCkFpkT","layer_level":2},{"id":"b9b25676-6bfa-41d9-9558-05107be3b608","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"PostgreSQL连接器","description":"postgresql-connector","prompt":"创建PostgreSQL连接器的详细文档。解释PostgreSqlConnector对PostgreSQL数据库的特定实现。详细描述PostgreSqlDataSourceInfo如何处理PostgreSQL特有的连接参数(如SSL模式、应用名称)。分析PostgreSqlDialect对PostgreSQL SQL语法和JSON/JSONB类型的支持。说明PostgreSQL连接器的性能优化特性,如COPY命令支持、数组类型处理等。提供PostgreSQL连接参数配置的最佳实践和常见问题解决方案。","parent_id":"e4bd9d6a-26b3-44a7-957d-46e0c9ba5cd7","order":3,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlConnector.java,datavines-connector/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDataSourceInfo.java,datavines-connector/datavines-connector-postgresql/src/main/java/io/datavines/connector/plugin/PostgreSqlDialect.java","gmt_create":"2025-12-25T23:43:22+08:00","gmt_modified":"2025-12-26T01:19:02+08:00","raw_data":"WikiEncrypted:0slJAk0S9iJjTLO9xyEAJiGzQ680VRl86d7l/AKgwYztszmBqTMeMWonK3c00mEuf0TYvziJcVFfPHdRvDhXpljJhquVuQ8WUEASzpD9HwZNUC8iaZcmQQKFCdU/1ESXH5TYqbeE7KQFLuVmlLmBl3EBLjyPvrivMOt5YZDeXzK1TNc/2+wROXX/35Is77+ykYYdyd6/RY+3Gxc7OIiVChsn7IS5HWqsm5qMcvzdycoh4YVAw8wlZ+gM2VXmmjl7yTlL/6AjT2qBv/EbFWCpZWBST8FV0IEAF6fFTzwd1jQ5Iqx0/GOHnRLBoH1XNdFCpelpspZpziW0AlA3c9UTgoDXR7HH94oO0+9dlRUJyrJtQB1SmC3P3duxuYovRNp6zqMJnt9fZ2hMBPD6eOKDQKnvKno7RyYtbgVOMx0XJyR2wGF1TZuhCjQjILUFAvmARi0Y5Byp4Rm/hVyry0B9GRXOAjogz5oU80WnGwWsJbA898G32Aix5oS5lwbmiT0K3O+oWLV3j9iStJy/Hf4WwNwA7GPuo1YK2zzD0vlHBYGJa4BFMuHMl/tUWGH94ffUOuecKv0SE1Ma8OA9+36dbPCMzCK+/pTrXN99R7qqz3E+15pcqvwzej42JtMVqi2/MkMh0sDB9TE9M8ODVH+tjEfcm/nvhgyOsMRc3bgIAROrCO43QgdHU3BoeUgH8/ueksfzkBm3FnHUjaDTflXKJCTpXdIqIZVlu6YoTcgJPjgNIHHnt6jyKCEyuPkek/PHfH5WFyva4qQ+GQHL3+upIczA0F8mHPuF2e41eqdmqg4KBJFejRtnBuSlcc5dTrMtYkGYFliIu7Tz6O8syi2GLjyq+m3Jkh4VVvq3uEClgfX+ODMwPytM7MJ4lyBnwFuz1DdVnFMSUu/hI5W8qZCqCeg/ZKXIFpiwgf+gbyF/i9toTZCQsjCkq7nnzO+JAm1RldgC3Au2o66cPinWeIlfWh2N8w01EaswJQFqQGOFYzTwsBb9prKZqy8momn5vrKmMgktB+IV44nwjLIPSC7vL/gw/ZdyRFqos07EpQ+keAQ8/8K7K7oRYcmOKv/lMWfexJCQwFc6r2MarqfMbnrpu+1AqJqqgPtBrrJDJzbVII2LAOsxvP+lh4pcaUsAmFpBxQjBo3qusQ8JDgUVWBgWYEYVxulMQQtfgjSlvA3Bm2lwD4kaNL9YvCWRYWh3C4OoFwZN608y786xOfCD6blJpR/GeZinBwniZ4OR4RrPIPGzbSl8OlWs9nam7y2mbjuZ1k5Rxw8LB3sxDb3Q7gYR4q9ey1sn5/LAKIALWmGPa4nF8YUv7K+EiiKTllu7pNWCny/iQub1mDCLk1cKxxY9+j2q37Nc1Y8+Xhl7ZGeohMwS4j1+oawybK5Lz5BAYI8G","layer_level":2},{"id":"5dd0b02c-33a2-4854-9b60-5447e197432d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"结果计算公式","description":"result-formula","prompt":"开发结果计算公式的详细文档。说明Count、Diff、Percentage等公式在度量结果处理中的作用,解释ActualMinusExpectedDiff等复合公式的计算逻辑。分析公式插件的SPI扩展机制和执行流程。详细描述公式参数配置和组合使用方法。提供公式选择指南和性能优化建议。包含复杂业务场景下的公式组合应用示例。","parent_id":"706d1a2a-8449-48d8-8a21-58483495929a","order":3,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/Count.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/Diff.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/Percentage.java,datavines-metric/datavines-metric-result-formula-plugins/src/main/java/io/datavines/metric/result/formula/ActualMinusExpectedDiff.java","gmt_create":"2025-12-25T23:43:30+08:00","gmt_modified":"2025-12-26T01:20:06+08:00","raw_data":"WikiEncrypted:Epdytsif0BKqv6RSnKUYh5hP8+Pmry50vUP+kEQyytbgjgPiLCtjAj9IpSOixN/Fw2rlBKy277qcRCLF2LHFWc/7mKb7cuD6MsDJiktY0JUKcRhDh5V7FxHPubK6DpqOfCfpvj8d3geyb8DYht6BHUIFwcuM8C6wlzdzpoNuk/mOJmt3+3Q6xa8uVbG5t6xJCSD4hyF3PQVk8wiAZAsJ1dttUiLcmliRNIfGzu/Fbj+5w6Ezn8KlhyC1Muy6P51NsB+BdSi9cFEiDkHPJ9GfGlrCumqicNFqOrcjlRTNSr2T8nRkEnRydIGCqqiedTtG6KKDqN712/3mixjxQ+R1IM9O2e81RnF1Ao6ZJY92WB1Qb6NSLgt7zdThIhClVAMpmX5K8r8kww1UBWZF7EVuIRkqHm+SUKJ2aNzOcLj4KsN6mF+kSsY2mI7ElE4pPzehLUMIqRonKr38fLmYVQKcc3Psh6Aju4j1nsxiWMkTmDcQXyRVIUdqn4ByhfMpLbPGzkJ9m1+Nvagc9hgy6ssuFAh5DqMs8hiIEcI4HYg8Lajj6OPJ9u40OyGlYdTX2j5bl++AyASirYepqeAYVdA7V97Fsq4xnukpW2FhguVSgeWqXbua5L8j1/RNyY/kbWrlJ2eUWYijCoWOhUEAfYOHvZKAoUGHfWcd6scT5We6EXz3ym3Lftlb4j2zxhwYLr2CKPLPO1wTPjvWhHQhDlDl+KTXcBx1EhBi1LonPi9eS7FLtQCIazG1fMjbbeKALVTAa0ReEAKibzr0TUPG+6SvnNtIhtirOdMw/hYLRmZOhbYXJGid2b0D24FrRujAExMU5cWIuuoR9h/iF6vtmp7dgrt5ZhmhjjdVH7m34CnHtD5NlmgkeLS/6aZRh+iQYxICLaQGcQDU0VJQiySGQOG+bFGu2pOXu7haFPU3vm9aHQCaAuwGOY4YOwicWOQRmNr1T5a0lk192BoOum9ZlW1hPUGnX/Vd4c+KGFHreoNIsHMdagyD1h7pF3a03XYJS4h9JR156Gu5xR+HSKqPRPmSPaX/8Hc5xctEkNjjVcBIkRCMvjqK8zkoehuLL09CXtTVSmBGnsmYrlPJXNkV2BSSWat0jc7WEL9O4Lz9VJDa+GSR44rxLvwAG0ELfxEv+SqteIYTvZamr6TMi+GSHmbTd0P9mimPd/ncwuWMp6+b3yG7XnMjQYZb9SJBeOV2rgLbrhThPdPE71VNcrGgNFl/WwXj8uP5js3ou6Gr7IlKaeDBAIyAiuIV4Sb9cFyR4gNLCNGXcjTybI8tNr5rSlf5PYoMCRoTNAJxcE8yEZX8dTcq8RREFJM/f41xNDZ8kCWS+DjjDi2dT/uC59P6V9+DZsRlqcFlPkGIqysV4MXg45DvhuMsnKJ63P9Uu2JmnYDMClCK17VVnP1DMipCkcXMvNRM/mHzIG0oZ5YtzCsSldc=","layer_level":2},{"id":"43bcf23c-8363-45c6-bda9-4f0d569ad332","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"飞书通知","description":"lark-notification","prompt":"创建飞书通知插件的详细文档。解释LarkSlasHandlerPlugin如何实现SPI接口,处理SLA事件并触发飞书消息。详细描述LarkSender的实现,特别是对飞书卡片消息(Card)的支持,包括CardDTO、MessageDTO等数据结构的构建。分析消息内容的组织方式,如标题、文本元素、按钮等。提供飞书Webhook配置、消息模板设计、自定义交互功能的使用示例,以及处理飞书API响应和错误码的指南。","parent_id":"9b0e5495-2217-4011-bc46-1d550de3afd9","order":3,"progress_status":"completed","dependent_files":"datavines-notification/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSlasHandlerPlugin.java,datavines-notification/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/LarkSender.java,datavines-notification/datavines-notification-plugin-lark/src/main/java/io/datavines/notification/plugin/lark/entity/CardDTO.java","gmt_create":"2025-12-25T23:43:41+08:00","gmt_modified":"2025-12-26T01:19:49+08:00","raw_data":"WikiEncrypted:hSln5ykr/8OMXxBfPaPu9rjQECZaO4ViBLZu7NnplXNr9sjYqs+eywq90PYiaDGBu1oWCKi3CEtXcLAxrA6NvZrKyvMpmWZG3e82nMMPw76TKVkAb4V7gEsQzHDVXrzNj9oWz8f5+QwF4EpehiNNBKkK+pQwx6JCYQljfTjFMe+0IBezcl1BiXbFZ6eGUt4zfW0wQuuh5XmBaxMnatsdMYP7Ibg2aZhrtHrUNcZEPmoWYjavzmSL3vZ8zij7jI+7RfskeueyMO9qYplEFJQ+vpNI/52VkpEgewoYllLst41CDTrEn5f+ClTpXGFoILecySLqehROHNuL7+TqLdqLdFxoMHWGwP5TiSa/Q3KUREUp7EaJ9akFZ1u3ZfNNQ9qTv2nPJE4Fvh71V70un75hoxF9+5TTiYaU8Lawg0Yed3Le7CNgx6somN56UF5JW18CLp4KqjzEaK+o6PZevDa+BaLHlWaJi0KCuJHTltD1si5bPUpL+yuS8UujSXCw0OQrko2Yhl9w3koLCnBTXIa+eU30aQ/6oaR7SckI5+31acPScev3Op0rdXbNQtXgNLkFziJxK1I2BEXkakO8ry+rJ3brSsAY5+3BucsJfVQbRCYpJYyMaU1m4mi8oYPAE5kbvInEh5nlFa/pYrrh/TD3LrPYN843ZkjvmALslcyZ0kEvNoJFHWb1ysjIfMxTpLsVJOVJUb7M4qSDER3r3pxOAK83bbQLhjfDxzntG8RzWSuP7tku2VlhzxoGbfKNTnyht3a0BMGyjW2OillIBPtrJYzNk7DR0VOSBEc/Y/O+FHYlSKUlLAHgtxipBLe62qJfWYk6o6fNWdWQUv3SeGB9aPZwf0n6Fs2cpovgjsVOwTxjpV+WIjxXNNu75hte3kCs8q6kLAQNhpfPng+DSYgGPyN1rQXTATIJufXqW0hhE91cLeD3/O0Dx2fyLD6W8KXHjLlUm/oYVc++aQWUWNJAKxU/MZEhTlrgCu6hznDTBWlDiqLqSsXPJgJmg3A2v47Kh/g3tqgBjGS5YENewoZHaVyOijdwHfkYUHgXMZuYbKuuiQQT82gNm/nFDSb9c6ZwhN45iPnfdLlh5/siywPc6Fg6/8rtgjhgGSfrYZEcBFgzq96XPQwri04y2Xa1vvjyp0Jz9h/saiFtZjAJ13EUsQ9wGuHS8kmgwDFw8eaSLXkispASDzqStkiZV2WMDrUegtUhIj8RMQKYALbODPo8Jt7mffvuz+W2ghDwwMMcSdfYrhv8xGX7ooi9+wio9wnDX32c2PvctAn//D7C5KbaKhGX5RYtCxiinOScNDABkuskKV08dEblhtSoXRN+7kitUPts/wJKZY0ij2xvODKH/JhAKxKPG5+DbSZOlekl7p2RIzrp94wd2KVT3uemXSoalm5z9rbs/3aRpcC/Es7SzwwCWXar2p6hqBn18mSCGkxEqTJjLF78gc5h0MDtelT2","layer_level":2},{"id":"b792898c-8eac-4dc1-81fb-6d553602e3c7","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"API集成与数据流","description":"ui-api-integration","prompt":"详细文档化前端与后端API的集成方案。描述HTTP请求封装、拦截器实现、错误处理机制和认证流程。解释Redux状态管理的数据流,包括action、reducer和store的实现。分析类型定义(TypeScript)与后端API的对应关系。提供API调试工具和常见网络问题的排查指南。","parent_id":"f6fd9d61-f5fe-4cee-a269-b29ba2583618","order":3,"progress_status":"completed","dependent_files":"datavines-ui/Editor/http/response.interceptor.ts,datavines-ui/src/http/index.ts,datavines-ui/src/store/userReducer/index.ts,datavines-ui/src/action/workSpace/index.tsx,datavines-ui/src/type/dataSource.ts,datavines-ui/src/hooks/useMainInitData/index.ts","gmt_create":"2025-12-25T23:43:54+08:00","gmt_modified":"2026-02-05T02:04:29.1556156+08:00","raw_data":"WikiEncrypted:Hg/IClp6UcmGXxsUD6wCXMTYpyU8EuhfMcfBONyl+OKfuGunIeLg9qYQlzFXL4P4wzuMKbabHUsIiVN8vjq+VeFIyhcGx9kDqeohbSTK0g8W9b9nLdKbaL2iwFPVbuN3aZgTx7FmSJzgcsDUDfSMFFJWc3Gnn4JNDy1Szs4h492e9wIX2C76ZJUhJCmL3lVWWRhndQaodwulBxVziH9GscVc1pAqDJxJJFDTHQAkkbd+VyIPWOjVtV6Cj1WNoxJrkBVYaCCXztImy2xUzWUZxvZWSSVxGyEDWNhqe0a3zIzxKx3AeNed0Yc0FolizgGP5IlzkSZTHLlu3P78MGfeGetpMJV5kdhJk23nB5ytNnEPR4mRQETkoDp912ZgQWs07H9Jr6SWsDGR0LeIYZpzBtI0MeSPsUtpOULnn9AsLLNPM32xGgqiwklVbrHmZMiniV4URx7MALnNucBY9j1eIeW+UGSXTJIqfa0AxTXav71h0LHcv1k9sCLwiJ0R6acE+UfW1McDSoOfo3NYFjh9DSOUnE64qcGlyIxPPKcPxB7JAnXHiKAk1jiwYAuuYliv52P6eeqP5sDJvr0/uslHZDMdVQf09tTJ5KrZfdMXIzjtT6I1y51/7eVj1TlZTZVg4XL4hCBF/0IGtwNeXZTZ2I/QWziA38j+P4zwk08dapZmu6oBk9/DTPaF2HBmLkRl1MfZ/hiCWsCRqeA5ykggK7Cq6Zps9Mtk+lcJi+JllKJzKhRgD7mNZxFQPfDjadszauGrJ1X/lX8bK9j14G6ukfDvNpvhkJ8WHD5UdblBNHydg7AXhP082atK+XHehNhLXHRXQZfN5YQCtJeX6edqySWyh7hB4Ksn/PDFjVm0nyHFNUL6uwDkOZ3OSvaYEXRCziPdFCdQOYimP2NtFceyOI/EAcZdiKDAzsIivKDxmDF1jWQ/swuRZ7gj9vfUFomKwIX0a6hmNj3O9eFdWnNpV3+3cCCXQbNyTG5kEfYBUgInk3bFRQEYUP1yWFGZWZDjizlh3yjAzXaO3uBxm1FYnL43a7/K7iGznskrXPCmsN3kxu2HMCuTm7YrcnxyLFJL","layer_level":2},{"id":"176779db-46f6-4869-90b6-039bd05637dd","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"用户表 (user)","description":"user-table","prompt":"详细文档化user表的结构。提供完整的字段列表,包括id、username、password、email、phone、status等字段的数据类型和说明。解释每个字段的业务含义,如password字段存储加密后的密码,status字段表示用户状态(启用、禁用)。说明表的设计考虑,如使用唯一约束保证用户名和邮箱的唯一性,使用盐值和哈希算法增强密码安全性。文档化该表与其他表(如workspace、access_token)的关系,以及其在用户认证和权限管理中的基础作用。","parent_id":"3c7fa525-a12b-4451-8146-b1bcfafe2f1e","order":3,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/java/io/datavines/server/repository/entity/User.java","gmt_create":"2025-12-25T23:43:58+08:00","gmt_modified":"2025-12-26T01:22:45+08:00","raw_data":"WikiEncrypted:XeR8leeYfl+L7QviTQYpg9y1zUH60z12QxOFYWgVT82tqf+7iWfzo6hanJdRP0KnYMADM1zAln6rY70Fw29nsl7P1bmL5QbkeipsCNIYIacdiJ1rsXclhQgrNtdlNb7Cs5MoL+vQdrYKeb53gXr9nnKpMiDW4WI3Ph/A+g4WmeHxrvyIjnn1lTwJOvuBR+RrW/T8KPJvLXvaYISr2drOIsJNXESgHeL6hqU68F871Nhea5sdu1W6LYeh761tMzUdwerc0AgvTa6DJ/8R/hpnb2Gy5X6sG44gux0zMNglJ22VvZ8u54SAYLlsij7Lxf7kIBxOLAIdZ77ynKu3qEm2itx3974fWWGEyA5J3XP/jur7Cs60NifVkzjbHzByQDcXcAkLs/vKHN+4b7UyHHfXwH3K1VxNWv8PKk5q63inOwMALS7vBgGa/NLed/hyFplKM4tkwKL8NxLLW8IS6B7m+GVKALPTQuibXis5AV6ZsQrbXrnjXHoG5tz87VmMR3hd+F0R1ltdUWrMIH2JANovxSc+VRFWXq9zUlQjhc8cWrJ/yfzMGWTKnyPVh+j4ePAiEyrNYGOEYKewNJgGu6x9ELRE6DNWAui7Da50pVHZdGbxNDkP1iBMpN9UphO+ovh35liunlNwDIwF3wlqps88jRLAQHNrBKQtr+zhORF9ztJdhqNzpji2/KUbKVMsQYb6wBuhHwwnOKzmXVCvMVLKxGA5mWDHkE/RiU6e+q+bv7OgHUq0bfBXoCjyLzUaMQ6U5QyBxPW89/60kJ8kKRiOag0d0TzWaVMHzegjWzkWOrNTL0gsrrJP6p3nqReo10lIhtvvqyeYnWkXK061TTG7inwRjvHDFAzajtPSR+uOmZPNJfER7Mky2OgNtwmq5g/vGhLeOncXaHxJLkvyDIw8FcOIRvYJLafPf/ncIsPEZRziJwPjkui7SQ356IlnyOw2QYCXZ5jxDZb+mSsvWovXrhGMyhw+G1Luip6+RMVdvhROE0oPQfBpZQb5/AnBCfg+iv7ae8YF6hGyhSaJyKqS33Q+AcRM3cyLhILlnwWFGtjzHxpKWvvDp/dwmAFzU6+OMgU8ErjrTS8sToIYZSghqH3VH+d3MEbuB9VTioaDRpLE9OTRAKxVjTajF7Jyv/iiDzHJn4lvTcUQ3naVxsmUFHfr9o9NSoKkdz+4JOINCEU=","layer_level":2},{"id":"13116af1-c143-42c1-9e22-8310128cf4b0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"元数据同步","description":"metadata-sync","prompt":"开发元数据同步功能文档,详细解释CatalogMetaDataFetchExecutor和CatalogMetaDataFetchTaskRunner的实现机制,说明如何配置和调度元数据同步任务。描述同步策略,包括全量同步和增量同步的触发条件和执行流程。阐述同步过程中的数据转换和映射规则。解释同步任务的监控和告警机制,提供任务状态查询API的使用方法。说明同步冲突的处理策略和数据一致性保障措施。提供性能优化建议,如并发控制、批量处理等。解决常见问题,如同步失败、数据丢失等。","parent_id":"493d76ff-0c76-4864-9a2e-0a1aad23f133","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/scheduler/metadata/task/CatalogMetaDataFetchExecutor.java,datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java,datavines-server/src/main/java/io/datavines/server/api/controller/CatalogController.java","gmt_create":"2025-12-25T23:44:08+08:00","gmt_modified":"2025-12-26T02:21:55+08:00","raw_data":"WikiEncrypted:pjGuIDHO+JzqEKf2Vs2HOjJ5axk8xuOI201cL8xdk3WVsMltDfCQ6DHG+Xvdal91sVHyoFEyijisrWNUSYu0+H0NpfgA+IBt9v9DBU7OALceW6j6jc5874VD6dd6QVwOVCpcnHPgteAPr7Wrlih1AA/ZOsft2DHcqFeKqOoWaHJaAIrtSiuebb2Bij8ZnEpByLzSfs8cdhmUyn+RRneSxZ7ivf4YIJcHJa3l3gFu2peNj1bO1xrG3u3YXOb+WkV79pQKpnc94vFMfRyKLqVrjGuK6yF+r0R2/GjS/5jP0E8PhpEn2PllObZ9J0shWYMZnY68NKHgJqJNXH+U45jlwvmcCMrXWhzcLjvjrxBg5akT3NZIvmgOo03ckBB5MYC0Okgoj1TTHYou5suA54PoQYojr44Zzx1eviy0qlZCtFNHRVLQ9/UuPWpW7XPrfxp9c7zxyXYUo1wQh9XbywbvpQ8G7m2a0Mq94D5U+bHYcwTdS5g0aX9sar2vVibDuNWI4oxONUqoalALqeQf3BDQZqfPRtFtcvhwoT3yH5vd2Yt+s9/ArsY19YhaqjKIRiYJmUzFsBqzfEiGaZsx7ksauxjmmcLhJE5tI6PSdyIjTkIqL9/ZCx9v4Phej6XleM8klva5kBMvxIVt/YruYzUs8QNZv/evRhf2sJaq8L/t+lXz6EAYoBt5N6ASM3STSxT/FUBEgqKL0hAKpAwzkzAQIdPhrduD2rwPUAQuTgzYvlnB6cedaXM/t2nWvBwbQbLGLEjFhIXx5gfWvnAjuOW8/S/Mib/AgSqvRkAC2qarm3lwD/cFntuC72r9bnk+DTWtnCdWTULlctyc7W/Ms5mrS0k3ai+G19MUd6zzyMNmN6LKMQTvupuYFF2HcQj/0QtSAmmT3wF5gK1qZ7/VO558F2Hh9B2g6v7yfrFbPSAC3TANaV6UvIZ82+t+lbXH1SH2Z9jkH1ShelqKihvdGM1vlGsF2139X6zaD/LdBQHz07jpcgn/cxC5oV1v34bSI2UJD3r3hOpRjtEhD62z/Hn8DkIcUGFj6WRi74oZFa4qVP46/YAMC6geR7EGlZhNVqSUNX8hD5vfuyUiS/uYlXN5SP93bwX9X1vZw1PpPG2aBTyyx9V3L+oeCImavnmABOyY1e7sEVPSXCIwa7pIP+QToxuzPKXhuHxKVfntv0WjlLpaPf0/8yYgukWL5VXqVpE4C74MjIbnTt8ru9t2fgiMLvAbheHYFrCFrIyaORR5OBf3xqjPhYAGIrar9aTOeiypQE4G9nV81zmUvMwIrUfb6RpPokjZtAtLtAXdbOIa7xmQTmupNXbVsqdPcBjPygGvc1AHdp/9s5OBobxBdxKU8MwRFfj7ceWgB3Dm5iA1FuxChv1ITiDPXh10/g3T2J35hz16XpCX6UgaY3blH9pomQ/FoPX+UDCctbxMyjxgVxY0TIP1AxN9paS9c9Lx9CcM9P5XOPgD2yqHH3aCj3q3nD8MvvefAknqAIYSiMsvv/E=","layer_level":3},{"id":"30baef90-499c-4bee-8229-830bfa4edb83","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"审批流程","description":"approval-process","prompt":"开发审批流程功能文档,详细说明DataVines中变更审批流程的配置和管理方法。描述如何为CatalogSchemaChange变更请求配置审批规则,包括审批人、审批条件等。阐述审批流程的状态机模型,涵盖待审批、已批准、已拒绝等状态的转换逻辑。说明审批操作的审计日志记录和查询功能。提供审批超时处理和自动通过策略的配置选项。解决常见问题,如审批人配置错误、审批状态不一致等。","parent_id":"586fb977-73cd-4d21-81a4-ecfb619947f0","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/entity/catalog/CatalogSchemaChange.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/CatalogSchemaChangeServiceImpl.java","gmt_create":"2025-12-25T23:44:09+08:00","gmt_modified":"2025-12-26T02:22:37+08:00","raw_data":"WikiEncrypted:WdvChTXRgggX1kupBFtcETccyKW/6ju6BbdA8oufc/M29WhtMytdqbfIOsIqFOOZqfYnkiKaPRf1cTRveLnrLepOCJKuvPgymISPssKElavuOpemjhl+wJFszmlwk+kU9EOmNWEe88FhzhUdmEwYusg9s221+xAezs13P0vjvEbHsDu7VTlCIRF1iWRzGpmORHGkx+9St/9/1dLKgafHCJ/pdF4NtlScFVrBc/sZ0voDIwoLF4rCzLxJ3EGoZienI6LiUbts6q4LYt/gQclwTRtLMX+xkK6+X0h60h8tVAVP3bk6RnLHHWWJOqjOjGzqK9OiSGFvpi6bKKaHQsppWmzWiIVuukDxuAgGMrvDSCdi0QHywF6IPOdcFkfPdEl/IhauGveCCgia8pyVzrmffSYOv+UzuVrYdggHx/MVdBgvnIfdEWWSpVb2i9ltLZo5b0BC0dQomuGEXXjUxQAroXA6iFT7r47Le+3V95U7kgs4iPm7fssLJSAXiHpvpNWlaudAMACEdz3JHLY1vs5W//aH4CcYskEvidEcjg2s9Wg49vlRHSdgpT0Cp4CMYvyZauGQhI8b8r7lVntz8/xJE6TCTTkfrxYNoia0SPrsCyZ3kXCV4zCHSnVANcmOCEy/6zBu3KwFbHI4fiv9muDEi6geg/SoS3gJMLnTxcRnCHnnZ057+mrp2jivuS74rmXGk79DCsHMVshK+tSTQUzb0ScT8dgdw5hteGM/H1DhpPPgRkbIxzk1XH84qC05VaPwBYnS+SET7i674JEUjFQogaoD4rjtG63T4U5+VJZxIZpsmYaNdJIM2HbMAjUy75aL9lYC9nLRJFRCAS1LOz5UbgGpcgBgLtyUB7J+DtqH0k7ByDOBhN7xpOraSkwxuBW2UA5LR+/jQLHtS1MlUZ0eZ1HAdWVoFzuLum3a+ULyrjJltwBisfUFSgkXgPSgfa6kPqqds2rUuCryVIQPp3lsCHVOFLve4qbMQrVr0r6cHrkBD2uHaxCBv1gUMrE4GUIG27834CN9XsZft/QIcFNBwCFww/p8YabkKBlGGJkw4oi5AI3ltmVkXsmZNfejoXtSBovLN3Sz/gGLcv2jtpUa57lCssKKv1JDvjPlSUUxKt+0alSb7yn2DPMTKa6Du1fLsltbihyRDeRTV2+yQAhxShUoBULxVc/u4Vex11aFqvEARJVyV6KjIPjihNziWhiz+wZru5PiVKR3ziTzGJXuQqoqU8pw1b8Ejp0Eg/0nH8Q=","layer_level":3},{"id":"10fb4d0e-6886-43f0-9f3a-7e3c1e6b8221","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"性能配置","description":"server-performance-configuration","prompt":"创建DataVines服务器性能配置文档,详细说明影响系统性能的关键配置。包括数据库连接池配置(MyBatis Plus)、线程池配置(NamedThreadFactory)、缓存配置等。解释如何根据系统负载调整这些配置参数以优化性能,提供不同规模部署的配置建议。说明配置对系统吞吐量、响应时间和资源利用率的影响,以及性能调优的监控指标和方法。","parent_id":"d6d39194-b46b-450a-9e23-15374a060630","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/resources/application.yaml,datavines-server/src/main/java/io/datavines/server/utils/NamedThreadFactory.java,datavines-server/src/main/java/io/datavines/server/config/MybatisPlusConfig.java","gmt_create":"2025-12-25T23:44:13+08:00","gmt_modified":"2025-12-26T01:22:27+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjM7AGWUhDQ6msjljzyxREbGypW7zTXOxX/UfxLcRpBSeYvfeZv3SXGo6B2jDN6hc+TdwoEuUTiVF/sFQRdHyII7q9U7E1qsJ6xHHo1F46LU3vG+Y8V+q3bxH94ZdPo1IjT12kDEgR3HE7k/EUqOrMPLXXfZaoqR21+QT3aGYSCa6jDNlGIjpOBK1IzvnvIX3fLFXQb6Qav6KjHXnuNRN7wcYJSvAK9JDStR0O3HRUFtRRBz8czVkaBKWetObDUEYPOdziyUtjEx8EMLuUts4ljKryHf9YJExqwVQNhki9F67HxjNway9IF72tkPY/89OtxtmG3Vl3YiOFDND6J9YbZW8/Piw+5PsyWMmJysVgfWaVE09PT/r+U5RQWeJt4f2QL8k19cNtqHkvrEuy5hk3ZfoLJRdNwHaOjvY/wcYRUJBEmFg6G9qh5LKc/zFiWHA9ZOG0IiCP8dannh8frFuWP8VZnG1EUpeAwJLlW2K20KqjOBD3NKb/oMCE/ncdr8Bdw3Z+TV1w27BQ3SvkBQBOkX5p6e8rN9cJZYJNejzDN7bmNFQda9f6IO987swvxIjcvZMk0fPwOqDyXYxyDoTUJF5/HSPJjuX7ptgxR0yjdBiKFnJytM5G8OtBWg4WL97YnPqsHa3h56RiylZny1RXe+1Kb2V5hoK9Izv3YIU/Fk+Mzv9TG7N4w4RrcaM2v99r6Srnj/MBBC3+T/4q9cz+SO9gD6NA7z/UlJ+mwFYxyJyRl3oU0ApC44KZI/wiPik1OAutuIJZDF96Dbz1FGZh6y9GRrV9NYNu4IC3hNy9fEzcbrJVceNCPY1z8Ufhc74C0FZgkB1vYTOlBGHOg/Ck993AmpMOMBsmdFNnbIwC7jjPqbCctnOsw/aM1E6R2vVWc4mIjzPer6ss/KpIY+Ga0dxNJHi5haItjUJLrxZbEsZsqUZl4DMXpULX6VtiXtN5PE8hz9IwSoJ5VRuwPRiKclULQ3rJoSJAWSGdYY3Guhm6YtXZjOJDBCYwHDFCK1kfx6NUPZub8DVCiPb6I5FSgm9N+jIRYdzLai7C8Rvdka0YrrEGXdEUdCKfBrc7y5NBW5cud9ornDH7BhPekDN2o3tSPWKrSoxZfPS6BuYPGZIlzihu66c/kY7FaCaLP8UIZSFiSZ80aPBEqgtVPJbCFDEy8JqHzN8wJ4Pq3RIPXJ+nbF30zuZjnBuL19nIR2hvBXuvwJa26iSzNKx9ziv85E=","layer_level":2},{"id":"30a874fb-babc-4cea-887d-d8993e5ae436","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"企业微信配置","description":"wecom-configuration","prompt":"创建企业微信通知配置文档,详细说明如何在DataVines中配置企业微信通知渠道。包括企业微信机器人Webhook URL的获取与配置、消息类型支持(文本、图文、Markdown)、消息模板的自定义、部门/成员通知策略。提供企业微信通知的测试方法和常见错误处理方案。解释WecomBotSlasHandlerPlugin的实现机制,以及如何通过企业微信API实现更复杂的通知场景。","parent_id":"8938d0ac-a871-4818-9b4d-dcba6e588233","order":3,"progress_status":"completed","dependent_files":"datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java,datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSender.java,datavines-notification-plugins/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/entity/NotificationConfig.java","gmt_create":"2025-12-25T23:44:31+08:00","gmt_modified":"2025-12-26T01:21:35+08:00","raw_data":"WikiEncrypted:hSREPKh1Ck3pS8vDc+GkCVmrynGYoH5B/FbffmsWVXCVttNm2/weZL5ZBLlDSsK/CkY3w4g2KYwf3CyQQ8yG2jl9/18131KiQuQXM40+dHvnO4Ngz06B2xK+jBvwrnrQWum493EsT4TjPnm5opcSXQgFo4ndcF/mqzrYTcoQcD3tJNghPz2Xs6zZSyLPSl89UOVAoNHd7mkfhEDYI7kOyI+PclltLClNilUBoVEqFsj8O4rxTQQQLwTw10WaqHZpZX/BnXxfI7Gw7vgNkK+CMmrwNMuwbFFgcqfKshn8bqteqzf3GbDjMqSrMkpYzNfIVapa8Gns9H4/o7z1q/SMcV8ml2eaGL+u05+5Fwpb3LgzF9RnJShGXVCR8C8daWoyoAbcndPsVSxQ8r5G+p++KId5ZF0thej/WrkaoddhuFjAR8Ucd7qmc5JA/MIvnzSXLPr96vemfdC6iBePSOu2LIV1/Y2VrDsNfJdB2g4e2dy2bConUOCRbLmNW71YHSZDt5WnurZDWt1bmgsBClK4nTEzW6nuRmwAsM6L8asQXnMWYXBvr+8Z7KE+y5i8ShasQzjr/LEujLVwajV39Zcs5l7mvhWE3Y9oXzGD0a+Rqrwekax44v4wA9yKWnxMs4GnZNvLs5VpvHvuyiHWqxQISR8j4n4WC9+ZlEJg+eyqGnBQKF0ecmKaa3C0ovwaBg9FBQczPK44ksWxyuhbVa4B2cJ9lOlGhwmyxPHHQlv5XQ3YLxQ71F/YESqltuLeELlhQAVLW02TcRzMi8bfO1dK8uZpdPzk+sa7bxHy8FO3RhweJUgH/sQRRFkuEVXrr/EBvu6WpC8Pwl34EKCE+XK45paZt6Weq63ANMjYDObV+/wPIXrSIcC84HKQD6woOCi6an63UM4L50N4HKqW6Pu3s6cKBtkJrannq8l0wa3l+X0NttNyGsS1DWd/FhDb2S0J4Hu2gPJaTXZRWZXcJTauePOmip2RMWloByoxV11mbeappcQvF0K7ZmCseYz8SVH4SAuL5Q0hSrO9IiyQjd92A3m7zRqwwoH7Gmi2ULj61SYMoeSOu1qWMgFMONmij4zQsFWrBxTk0z7iZNupdAGrCm8sbWoJu3YwyQJ+l6uI6ecQhDjMcd6ftN/m82VXEAPXcvFeoy2unRGmmOz872Ap8M05vIGBGhlMFOelJd2GdLSI34L/QGNkIa+Tro4trnZg26Fjhpj/jVqjcWJDN5HUxV6nVR6ICOs1xPQl2743rD4Z510zJrTkM8sun7vjA8tqJTkgwbMspwDaTTSB597/OHuN/D2KR5dxtK7WJmzCFQmFPVBTYv6vpOiZdHdZ9OEtOfTtsHVIwJWY1VN/LJwjQz51bV4riFg+Z0AFLlxLd0mvI1FTA5Oodsst8tb97gydFezwtUYyLuHn9mymIdHz3Ph0RASP4bz5PFF7lhlSPXIYFvIHXTjPEs1mdIxLkJe83SjhGcpZi7+8wJJhogDC9wXFfAzEt6NzfjXPQgF8CwcW3SBXlxtywQOHzkVVb9f9QhYteeLO5qdmDMfqCLTXjQ==","layer_level":2},{"id":"e27cf36e-27dd-4b26-a11a-f8f2af97306c","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"资源调度配置","description":"resource-scheduling-configuration","prompt":"开发资源调度配置文档,详细说明DataVines支持的资源调度平台配置方法。包括YARN和Livy两种调度模式的配置参数、连接方式、认证机制和资源管理。解释ResourceSchedulePlatformType枚举定义的调度类型,以及AbstractYarnEngineExecutor和LivyTaskSubmitHelper如何实现不同调度平台的集成。提供资源调度配置的最佳实践,包括队列选择、资源配额、高可用配置等。","parent_id":"69630b5e-3d0e-49f6-884e-8e9fe153a0ff","order":3,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/enums/ResourceSchedulePlatformType.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/core/base/AbstractYarnEngineExecutor.java,datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/helper/LivyTaskSubmitHelper.java","gmt_create":"2025-12-25T23:44:33+08:00","gmt_modified":"2025-12-26T01:23:18+08:00","raw_data":"WikiEncrypted:WRaIw5LcDrebk4yzceYz77c5eWBWYITuvocM4qWB37P/i9qGhkLOIZvhDbgDZqezje8bznh4XS8EFLmkVTpAOKZmELSUp8/u5JA82rQ6aEc7Db/mDsLYGfcFeKf0lG1Ol9ynbiDc2qnGnnbMUsivCIiISHUezVvjUvDJMG004UrtQ5LYuhUjDPtrEIX1N4d1hC/jYo7VwH+qVaYuW2dTaG+WDDisUb47GdgR6G+WG/Mo1ZbhQKFr3UPDmnVuDGORnPklwDicOlVa7eMeBZAtww+5nj/apF6yyK2HLxAzKCcbYAmFhraeQjLdHKHmP6jE0POTuKy4UnQ5t0x/HKTWKSLWIfvsfJs9IzwUJV5WrAGDctBLvs22cY+kDpSSs2FNE2shf/SZlaDDkqdU/l12TzsRFg1ShmKBi1IdeyWsJqwr0v3is3HYXGBD0WjN44doAzMSRmKMRIeEKkVZL2Jxjw8abc11KTVvHasnuwwoDX4KS6mpss2813jhLMPFMjADR+RVfupzy9YEZyp1GXcEI2VU4dOPW/4YUiQTmOX4BjJ4iNu4CsY6mPOTNL6PH/Js2JlFJ9qmcIA7l/ZATHTjXJ7X+mI9xdAsq5ZjhI3+mA4qpnGjvlrtjiUd4TDT8JJcPzIQJq8gmSIl1n2jBcooS5a5d0T07RSypQfhosuqwehmheMD43Bo5suw7/7PsizGHNpPbZvpsFuNr/G/aXSa4DnPtWoxajVFjQXiCdlFcC0IUrdFiO1Z9XNWd1A6Lmdrq/9Ya703D5Z+qxUqtvSW9QTkb2JYSh9iN0PifFihikJPD0SbTASUVsMhKfQS0+0iWlvmCbMIsn5wQKP28+i/1AYI1/9GWb9stP8KbABVdKrUZ1EuHXSxn6xjI5f6ZJu2pqXqFiOc3bVJUvp+UU35JjodqDINTQZ/1vhLoueoQ2rxaQhAcCql+4qgzNNB9b4maHSsytQFejyfoc7IU4Kjy+6jOQYYmqSUAhw5432Cf7/8GjAQu+Wub0lDipl91GeaKXliAliQxYapFFvg6X8ZT/pvOSwNEQob7tXn5/0ApD94w1pyyTGIDUmPTySNSPdzSF3bkD6LTGqC9BzqIT7KUkfFl0I2zVSYGSTA7MOvapPt9+YReaybkoRaQUXvs6ILYnihDpFuD1dk0VkroJ3YucK3fZE5cFmh3FZh38MvhFqauOrfsSWzcLYKiDhZs5UX6UlvV9CitlldIVTMYSwpVtH9m5xuCyp332SIIxCtzLQ6PDWEiBciseNNZNpYRjQDcSuNNsWOKlrOGa79OoTp/JDM+/wTWOjxuEyjREuXRIgzVo8P9yACIK2msl1ksgFtgqBmo6Zm+VsqZyifZGrMWaoR5YSIru+BVMly7lIkcufO73xmXtNGAne2HCWxaBC0wbUySNJr27FQfOe21Qh7wQL610sqlIQfWzmnjxaOWyDNoFIuSeHxPBFioxnWhNuY","layer_level":2},{"id":"0d218996-d4db-4607-b1b2-2300e988f3a0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"容错与日志","description":"dqc-failover","prompt":"创建容错与日志服务文档。详细描述JobExecutionFailover的故障转移机制,包括失败检测、重试策略和状态恢复流程。解释LogService如何实现执行日志的收集、存储和查询。说明JobExecuteManager在执行上下文管理中的作用。提供容错配置参数、日志级别设置和监控告警集成方案。包含故障排查指南和常见问题解决方案。","parent_id":"bbd65494-8a17-4b10-9e78-b360cb044f38","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/dqc/coordinator/failover/JobExecutionFailover.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/log/LogService.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java","gmt_create":"2025-12-25T23:45:47+08:00","gmt_modified":"2025-12-26T02:23:25+08:00","raw_data":"WikiEncrypted:y7Dzc7I9wPtv8hinf4TiKuKj/zDeDkhdCGEgcdzskboS4Dlhtt+N58sl90jUWkap73PSvgShFUq0Z/ICdXSR5rHFAwDTiZy+/X5pbGpyn/PzDLw9Ex5DvvcU37qptrNLE/VeniRxkkT/LwUtX6y6XKEb/ba4aGG0IR7uXiy2g9IVUJR8JW0ktH6zEns+t4NQThLgtMIgZt5SyTROTWm2/ID9YxtXbN4fHZ1Oh2qAhgs1o/6F0uVTJQz5zUA3nSBwXQhJDm9ofCzivwYe5CAm1gvjUJjumYJEwRvekuID3eVPFzz1VV1DvULR0Z5g1Xs43G7qNAadzmeenucBwaioeH6R7r8skSbX6LVd/qK2ueFSo/FS3ehk3ZuKMi8+gRX4b6/bOSuAWiN75NYkJJP+Cp32YDlWIyNlMSlt2YdHlTFunvu2kBY1dBmvzR7EI00b2DOhuHuvjarz597sb75xzA2/XcTQBemGLT5XLxJXhnfmh9H5XH8FPzCysXWUHbZlPFNl9dV+ALeN1yxfcVp1KlZMrWKBvD+bkZLSk7Ai2WarludSY3uCP9Gzfd025PbhW8ktakU8jqMuXiX3TLUT9uZU4/vZhJs6NlZaR+eTSMuhgyPiZ/8CpN3KktAibx61mt3pI3jGVWDx1HqRhFdeoK3pm9+MbeFXgdXHD6j40ejtxAK38CzQ+ftlmUYNpZ6DXN32FZe8HkWbCVtwbLooDnXcM2uwABNltLiLV5tnFpBJD1czfultZbARDr5lg9eEDQoF0r38paNCscWHpQllJNmaJa+tQiinb/ZX/ssAKUnOpNxlSdZFmtQn5bTYBw4wqpUo2tWHgUChHN0Re3DrNucPHkVIQyui9fC0iISJ4uflcqKPH9SoV6I/aZdyimz8cEGAmVyZ4RCEMeYdkoa52YThsidah4hBS/U/hvanrisEkQnSvZSS6gG9luSR4n+JXtlPIPhldfa7gL63HJYn5R4e0dtM6FjG8wkMKm6qZFBwamus/Y++gpfZHEefZ/OsBOPOWuiV10hwMndBnkp/3f/rnTm/gj/2UriX/DKPNPI+eIA8V6EabGh7ji2f1jnPdCKJ2xYDwoUMbCYM57azyeUifk2I+A2dqVeWSl2iDjKlQuv1UIuH7SLe4vFCiLTx+fMXCOzK6nrVPpOe79s3twmzcBr0E1sIl6acvu63w+KgBx6uSv5WXbOKCBBzh/Ua","layer_level":3},{"id":"d8bcc029-a1d3-4a7d-9c6b-37e0e94241ee","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"SLA与告警管理API","description":"api-sla","prompt":"创建SLA与告警管理API的详细文档。描述SlaController和SlaNotificationController提供的接口,用于创建、更新和管理SLA规则及告警通知。详细说明SlaCreate对象中阈值、告警策略、通知方式等配置参数。解释如何通过API配置钉钉、邮件等不同通知渠道。提供创建SLA规则并与质量检查任务关联的完整流程示例。文档应包含告警状态的查询接口和通知历史记录的获取方法。","parent_id":"251acb67-6d5e-45eb-b64c-94b11aa2ce30","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java,datavines-server/src/main/java/io/datavines/server/api/controller/SlaNotificationController.java,datavines-server/src/main/java/io/datavines/server/api/dto/bo/sla/SlaCreate.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/SlaVO.java","gmt_create":"2025-12-25T23:45:58+08:00","gmt_modified":"2025-12-26T02:23:11+08:00","raw_data":"WikiEncrypted:ryYEJAc5WBxvL0PZPbN4s8/OTh2KQinPZ1whp3UGMuPMDGVRxQ+9Y6xIBREuqRYK2eMvHuNk6NVRZTwYCjzTPfuD82/MDadFj4XpJpPyo9ge4OvdSoVQyRez8MTRwk2LcEFyQhtMtw43o+/9Dtpz5DZSu8b9oKmj/fmRP+SVxQU0gklmVROsk1mZpgI5OUGYPA7eCY83E9CuOFve33JUYJnSOkovDOlWcLfGAGGH1TGGTZXHEmKxyPsrQZhNqq4Uqm+jW2pDo2TTrQ/sGh1IaewNOS97UudiLA3cWgPJYS6YsRhohGsHB7SaJXUCHvo2HQqNnNOT7YnsY8NaHdYHHtaZsx6/wmgMKx+xY2XrsaT5k5U0I7Zfyyf+pkuhsEe9vh3hFHROJtfA6DVEn1CbDWOzF7H72zrSEn75H2QH5gH3J1UQsYXuNB9eDrfQ2BEmeAfmglJ2DmAxHm4ZH5uJAvGkgo0mwF6G57uygUrzh8lWdEFHe0aVTLhXGCnaMg8jT7rVLo6V+z79Dpfa7GYnCFgw5Dc90b2THxpE9jB77WEVESo4frqEXkaD2Y3CN9aV56HvL8ge5CRPeUiZg6icU+jJt8SEL1R7lH3NXA+VtZGjr+/R983/qzq8l6duUzlpkQQhG0+8/dcaOq6sAd6w9UDsw7W587iujTkFWWUhOqf4DJWwMDOgBCoi69DoO6cvVr+0TdC+ErubMYWYnwqKpuamxaztTVQyymlSHto239HWaVuUsQolTGkvDI0ClZt2fWUCyj8T2ofpVq19Y3O9mRbSYbdVVm5EP04TdsX8ceICmzoYLd/alwhqALog/4maBWIrL2TJ09Dvi5Ccot1O7e1vlnoggtZ7cuaou5pjeGwDVOEAfPfcWD3erda75ARzC0jsIEuhF1Iw5r9jEyBbpbQsgL9YgDU+SG0xwkHXjV8x9Diem4b9DdRGWxID85EXbrOdpf6ruBl4Yhwatsagiqqr83JuxkH5YNp9VAktiHMrTXo1ZfWF0CiLtAbYXDOQcjBV+ERDugpEtbTSgR2Cj3/vXnroFGnDe7HeCN34XETMAECJ9iYUD4D1zbjner5SGk3jInvUNGU8iNtGT5+teGOIh6z7ievdBzAWqq7awZh+nMJIogyS80b6oRzAGDvQkR+Z87vO3e3n/fiUs/InR5bxiHZ4lmh2KmlDwINcbiFwP9I5C93SOU+GohgKLdiQHiXeCKnfnJrZK13AZ2Ft8VG8jcrAR2DClSPEA447DDG4LYZWTuE8rZedP/5qWD+yU0oTj9/2qRcU5hGL8ehnKaQmCSoq5aY/nkNhli7s2En+inqzoegQYuAcspnrWUy2O+abWa6g0S7BCaXaY+A07KgBk698OJhtr0qP0c86U+A=","layer_level":3},{"id":"c01d3592-d2c8-46ef-972d-f776a6b5d2be","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"EngineConstants常量类","description":"engine-constants","prompt":"开发EngineConstants常量类的详细文档。全面梳理该类中定义的所有常量,包括配置项键名、状态码、默认值等。解释每个常量的用途、取值范围和使用场景。说明这些常量在引擎配置、状态管理和通信协议中的重要作用。提供常量使用的最佳实践和注意事项,以及在自定义扩展中如何正确引用这些常量。","parent_id":"724f7889-75f8-4bdd-94c2-bc5fe8255890","order":3,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-api/src/main/java/io/datavines/engine/api/EngineConstants.java","gmt_create":"2025-12-25T23:46:00+08:00","gmt_modified":"2025-12-26T02:25:16+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJ8cLEytft4KRmC7FVT9dCexwQHIxdfaRCn6WJ9HDyCFbhifhs/slwbH2Qy3tQLkFf3TyCSXmIQ0CLWw2Vu8mjbs9Z36pZYVWwIrTC9vpMXltiHsRsmQ4LewuVGDzKGWbTZ/99gUn3dBDbe2qLoFfi7AFs+PmhlRbG5KAZ4vaWzTaqFJYR1tqN28nrDflizvAfWGuGo8F88QKsprc378q1gCEUr6Dw5PsQAvkcsoTeIn16/LurYHc/36qfjhZWX20pxmdW2Uk+nWj9hWhji9fRsGTmPc3YX9vaK8r1u2zIVriRhLycLzrw4VkyG4K9A9M+9uv+iVs0AczxT7jjhKdi6g4ilkxmXQIsj5FtRrW6saAB/eCmCGlBEvmzvG/iJ7oOHrs9/tFQvdiM9Jks4ul1OnGKgtTuZMdsOHbwJrs/h2QKsj3Oev1oLP8Ut8IG/Rk9apcSnT3RJgwKEw4bJOZoKRzsDGVZdCHT4DPYfDgVadJEbhbrH2Ty/nAN1LzTs3436/mIAi7+9aEZ8BqxWhMvG8ecLni3cFQO6jLGwAK+msJZIu/KcQp6V4q9W7n9n6T9uorxiMCFXMb8NJ2toWDMAjj8pbNTchNDmEr1nI8hHqzDenqDLcfZltHcPHDavmocFlGw1P/GvbMNl0cqjCDpe2T5DWvfXED6aqgtMMJK6lBZF34rdNFwMNlZCEupB13MqypR5zgiOv0rui3wr/ZUPrDAqELRFeZx8lSVOpUeQ2zg815oQI09QVzfhbqT8PjMnshrjl6mryV7zIZhi1WuFFAgksPCba31aMyjJVeKBsbhGoERl938qwuLXcAP0jgNwSJ77uoT/aV4Lg/ew1lVnop17E7qQw8QBICEGEXswKdxsJoAxtPRW9UEMOQFk3C5Hjxhx/XwuJwkFJLIv4vyczB1TOZbcmJ9CoW6BI7OXLpmbzpAM3/WNfw7ZRm9oqzjg==","layer_level":3},{"id":"ca1a83a9-76e4-4b39-989a-87f57d2ef7e2","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行服务实现","description":"execution-service","prompt":"创建JobExecutionService服务的详细文档。全面描述作业执行实例的管理功能,包括执行记录的生成、状态更新、日志查询和结果分析。解释执行服务如何与JobExecuteManager协同工作,处理来自执行引擎的实时响应。阐述执行结果的持久化策略,以及执行上下文(JobExecutionResponseContext)在状态跟踪中的作用。说明执行历史数据的分页查询、趋势分析和性能监控实现。提供大规模执行实例管理的优化方案,如数据归档、索引优化和缓存策略。","parent_id":"ae9c4797-fad2-4104-bb0e-09c584c89e78","order":3,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/service/JobExecutionService.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/JobExecutionServiceImpl.java,datavines-server/src/main/java/io/datavines/server/repository/mapper/JobExecutionMapper.java,datavines-server/src/main/resources/mapper/JobExecutionMapper.xml,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecuteManager.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/cache/JobExecutionResponseContext.java","gmt_create":"2025-12-25T23:46:02+08:00","gmt_modified":"2025-12-26T02:25:36+08:00","raw_data":"WikiEncrypted:jMgId5h0EoZtwilIIkOV3tAfaSHQQ9e/cMhcsIjj7ltHb9pjHTw/XkcgvjO1BaJLJd/0MhWeyFBJipcu+nfqTcstncgmMlkM5FkXFxlRzYfgmX4SV8hqXdnAQk218ntnIxXi4LUoQ1kRN0c3vrhp7ZZv62iQHphNMIHgKl3ou9KTouwnhmRNB5TJy30um3ZjiRA67u8xCsFSqMDC3EUZd7m/LkBS+c19J8NtdV/BNdGfCWwQ/pfm1UPB1xgsSq1AwVBNlmUo1KYIfEHsFRvlclhmkO1iCF+kAVwdrKxsRnsg+/gtVcyA99f6bgKPh+q/THpiOBDwJvt4tMAnrXNIClvAuqru4T6GjZwH3k9d69S/RlK6l7Jk0zRo5gnTV5537myAn1Vtf+eQx9Yyy9a/t5DKQ3SEHask3vSneyO0MZ5zioCWUaZz7K76WUFJMCTX2wMZHNXEa25lVvo2Kcn96xrASU/83nCd+XyiP504A+V5gDEPDWdX+zePzGrpaNdBPZ8ti7wLUWNhdcPvl8mJ1LVLU4ehw1wHeYvcXSjGAIx+VtmomzoYQJy/lHfJc5EIEF5lJ5ZXZqxVRPQh7HKvH7jljGDOuJj4qOWO5TUCMiK7yw2JowqQHiS9edNNYf+o0cxvzoosiyCbDHH0vIMUo9l93HL3LCW+9dG97GVfVPsDTDtf+/aM/wiKchulHZmQNDX4IEoWVE9cHPLlOLVwBG0aU0lOSlrYp1+k8WtsojbtCaP+JHf8JSkiy9hedA2aVFWLYigOJjjjB/7f8n8P9tyh5m+f0sSdFT5jJ199H+OPbgDUhmz0y6oRA6HvucqHjZPiIOc2Tny0uXDnP0F5OhMXoJJiI6Y/Xnlq/HVE6UNvfS1Vf3KW6I+k1CyRcEGwXnK3jNodUqICKtKctfYmYavkfKbRuzilgyV5h2zHH+fXU83FUMpGmm3yVCPdOtV1P92z5Z7bF2DVNfOpBVztGdGBdVs8tMq2XB1R9ZA5aReuYv0GPmOVroKUOhV0BSNseTzd9UOcVSRlmuh0M0qsuYymLWVbT2Q33Qz/k2P/UiKCRiXXniKwHYnYfqyabgkb2KEIcLwPCcQpzngC1Kln7aIgvpsY5I1mHjnlR1oUoNXJoPhXkdPJDNQoe0YEEcOidyUTeJ8H1HuMiiskHFvpdRo8tbJRE0wvSi4cvl9QXP+nofg63lrE7CmZlFAmc4obMVEqVd2OTpLkOYHx1WbhLOeNxJ5rYlMKJgQWFmYB+4H13bhUSR6oyar9KEy2aKNFbW7XXYxu+ELVeFMEYFpwBd57xgekKP8CNeO+voiv7/7oq/3Cu1M3npo18ZbcZ2BSCzlxR5dYvZiKhwTOWsQmYBD0FnVhjYEKo5RD6rqfT3tV3xAGWMObbWYk5BPHfKwJWSpdDCzHXa7aHxeuCrEkWepV64nAmYm0VG9Oroft7VH7qdLU6AetSk11uYzvoyGXZwFkmSw0/Yhyn65jyme1P6xysm/Pe4cxyHCQeq/lHNj4y/rcjIvhFtgyRtt6cUdjrm6fGhz/M7IB+5L0MmgUbzf+oGb609EGFcQEb5bXtZ4btOR7VIz7Px0MAb58WMYKr/pEyu7wZWs9QVnIYuUfFT6HySaVHFz3aeRXAFOCHoKtL9Mxb4PMHWvuJPap/jM8UcS9SP/Ry5xWX942SnG5AiHWTrUjxUv+LxSYkyy5swMIlbH8lu7tWaibdqitmRK8o1fI1WcpEt8k3r+ArJmoWZLf5E5bhfh717KhvSP/SyHFLchuCV8J8uiBI2CpB1gVpljczfaFLZg61IhXSJZDedRMVLV/iXiTd/bcxO2IhLg=","layer_level":3},{"id":"cb56a06a-5e53-4679-9b73-2df6b523a004","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"命令执行处理器","description":"command-process","prompt":"开发命令执行处理器的详细文档。深入分析BaseCommandProcess如何封装底层命令执行逻辑,包括进程创建、输入输出流处理、超时控制和异常捕获。详细说明其在不同操作系统环境下的兼容性处理,以及如何安全地执行外部脚本和命令。阐述其与执行器核心的协作关系,确保作业执行过程的稳定性和可监控性。","parent_id":"07b63f3a-0384-4d83-9231-bdcd684fc464","order":3,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-executor/src/main/java/io/datavines/engine/executor/executor/BaseCommandProcess.java","gmt_create":"2025-12-25T23:46:09+08:00","gmt_modified":"2025-12-26T02:25:25+08:00","raw_data":"WikiEncrypted:+fyGQgd0eREU0LbdYoq+mPlH3D557EbCiCnYWesWDcWm0y7eDiR+5ohyTfJZ7kgW/DgzCNLBO2FhhKHKvVLUyCibNwZilpf9NIkuClt9tZZrcOAp7x7GdAwihlSIhe5jcy8EBa2QEQR7VDoPM9dTXVzge3fHBltSsMVtEQc2EXr49AdC2AgPG39zQmKmTuV3AA079SNlA4JOKa7pOJe+eEUKSQMfl6cXoJCcFIN+GgdxiYe2LacEO6sX3Yw9PRnbh0I5fQa4CFKMo/SDXvddBHhaLFkmpChxRseaRLRXUisTb7PZ0RrwOJn9CzSi25448UUIwZVx4m/Bt31sLnilZhmLeC22hFDjRUYfhQts4sdjkv2nfZnWzv64dvrTQspAatTQFghR3DoBBwIrRUr37ICdyA4yAogjRCBq43FnOlTQXX2Z/qL0e23+hQ9xWQ2NxLEQR3Zyyb9btApH4hQolxkgjR2M2NjFrMzMBqU6XmwgE+aeEQu746Q8RaRxaD+P95MTCwD3hpWp7Yi3gRK/VW3LFUxG57zB8qhyTMTkdXbWMxka2W+IbuCXLtVsJr1OnAQfjFfZ+AAhD7daa7eck0JuNChyyvHGH3Ja7FNweob+PThCBZDuFdLUloNscLBd74/02grWetlrwoJzsWkxOhkUrTcp5zJdDSeaASoLs4bljpUxUHX5w9mI92q+NTCwoMgts4a6b4O8zRrKMNstZIyKUCHtEXCZVzz7ZaScgzUWnP6f8U/KoBXGoY1tjf4V/STMVUjXC35z6KAzemfRJ+FtrWfzw3OAftc2f31KOd6AXOjwsEL/TRYJLkX9NkyRc7Iyx9ZQPx7vqZcu8d7ZJlAYElSSbEG14mFxUmUUv5KWLGf9ss8Hw1fATdSjTQZOg3zIJflZF80qlT0wvvIVrnQATWH96cd34TTc9tP8BY1ODkA0AZxrdGYa4rZU8X41gwOA+QTwdCvmyzF6glQabA==","layer_level":3},{"id":"aa4c55ae-1c79-4840-8841-48bcf9748aa5","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Livy执行引擎","description":"livy-engine","prompt":"创建Livy执行引擎的详细文档。深入解析LivyEngineExecutor通过Livy REST API提交Spark作业的实现机制。说明Livy连接配置和会话管理策略。描述Livy任务的状态监控和结果获取流程。提供Livy执行模式的故障排查指南和性能优化建议。包含Livy高可用配置和安全认证设置。","parent_id":"aa8efb1b-1c99-4fe2-a451-746364c7e416","order":3,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-plugins/datavines-engine-livy/datavines-engine-livy-executor/src/main/java/io/datavines/engine/livy/executor/LivyEngineExecutor.java,datavines-engine/datavines-engine-plugins/datavines-engine-livy/README.md","gmt_create":"2025-12-25T23:46:19+08:00","gmt_modified":"2025-12-26T02:26:58+08:00","raw_data":"WikiEncrypted:FM86MRbIHRcFErydqrYvsxXBNpRne7P+HU1cMyYurMykYfV4dXvVPQiYwL1aqP/E6uz5uKjBQ0mD9DTQbjvH5c8YRA24qs83bNyCTfMYiks/OZXaFMLcr/P5VM+RLtihqxyrzdF2ohhMzebDH7sKivt4Aixo4mkJ5wlkXnKaiDmZFmE5u4IL63aPzTBwnsrzMl4dobLwA3R6NO9KZgbp7YrNbxp6N4urifs291j2CVvLhzOUQe4Oa8A/QPVl224KZNSvMl8lPR24Nli9KeKcYk7Wi+qYm1FyzEXzOCPpXg3ueWrmzd9ZaeSXgPPpLN4bPDkSoSY0HuxmcklS9j61Mcs+TLAaAQrN8b6et1KG2Mw6uAwECr0K6s1+5CvmoFFfXF6qUlk/BB5B6pDMpx4Y/jLo/0GAsDiARAz+pAs3kw8PKhmlS2zlKQMBWA650kzTvME1U89YcemIUgtPYC0jO5itqr9O1ocrGWv+1cuhHmrhm+uTVDxuHzijaMyO52kFk4iV/S8NfNVl8dk3TfsTEH+j+EOUWFgV07rD8rfA/Bcu3IrpCXB8K1tJL5fdZW4FvjktNV70M5bwoZcluzytJuCwzV5ioKwmRBGKlqAU6T1nXtj3BZKKua6djN15wa1eZjpUWg4nAM9XufLDCNiM5quHDuybdtjQENHN9CmsOjKVt9K2zZouft9SPfd1R08y+oyNTGYBPChfHpRbjNgQRz+PHjxDCrotg59wF4o79MxLcBSRaal4y50iY5e6PJsB6/5WBaMKzWSlaHYFdq+BUWx+0/IcbZDrizGsrHUoWoVyELhHR8KmM9W4eUqN3rlpQj9JQxASaP7GI0mDpRxpP22Be6h7aLQpqyG5Evxhdzy+kL61q/KvY/+7jSBqtDaeqwl76JUk5TwFXnzs5w/5y6htUouIsl3suzaJMEC6BNsEmkxXQ28UiBiE3Cm18nVsWcJBzsmVFUG+efYVfBo2NXPqudLBwiGIhKbJqPyU3lVs1vyZ+E5TN8HGEQ2qe5tC","layer_level":3},{"id":"d19dc89c-4ae8-49c4-b55a-71e8b3fd7b6d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"用户管理","description":"ui-user","prompt":"详细文档化datavines-ui的用户管理功能。描述用户管理页面和工作空间切换组件的布局结构与功能模块。解释用户添加、权限分配、工作空间邀请和令牌管理的操作流程。说明用户角色、权限控制和安全认证的用户交互设计。提供用户管理组件的开发实现细节和最佳实践。","parent_id":"21179d81-91c3-4822-bf9b-316332af72db","order":3,"progress_status":"completed","dependent_files":"datavines-ui/src/view/Main/UserManage/index.tsx,datavines-ui/src/component/Header/WorkSpaceSwitch/index.tsx,datavines-ui/src/view/Main/TokenManager/index.tsx","gmt_create":"2025-12-25T23:46:24+08:00","gmt_modified":"2025-12-26T02:26:57+08:00","raw_data":"WikiEncrypted:saczMOofTRu3pYswmgZGRE8UhLfCfbeMrOKilyUXC/o9M3PP2zy+h/N+xDg/j94O6vjTsXBIbcC7o+qewt/khykaDCNrysudruecnsF1/ySp026nyzL1UQxB7ElyH3SG7+P8B8LZ6LmV0forO0RTCjrUSE3TXu1t+x7VPasQ5UbVUtmcBIVnd8YCOhx3Z9+ew3IgWCCmpIMGd9QMpy/GwIDCdzRxkqNHZ+ht4fy+5pD/FV7kVqfPwFUrudoYwHXzcnd+Bk9PMw3NJGdqGVtOiJvJsya0t6yVLi4WfarEsz8WJTeTO8ODcqV+l5hFMrdRnabct/FWtwFqVTCzyagTsJUqUPm/lAHff4Q+G1tzcsCKeMouZHUcjx8Q6UsBh+fO3he2HYazeK9vR3z3Rw5qKVxwvasDcnP07gtNoA0xumXe/NdZnFxWGsakK6W93Hor6zPPTPo+3LwjqRH2pJQ5c0k5LND+/o/hQFwmGVAP0T4bA+zUPy9nyyZcW5wuLDXf+6Myb2x/t7EOKlO/xvCitzbVXUbo544rEhOIj+/l0mH0fGdvsKdv8uRgFZbwOdsCQDjzhBPw2uDJ7q4nTDIgZ1e9bheFjh5zklsNC8fpL8kWquTGT8/bg3abOcW/di5ggYKlUvi1xdWCRqQRR/PhOShsi6j5puoTB7idyxU/T539NnTctk2OXkWbeb79w9t0IbJG9Luli7cV7XBrQ2jDVPXkMpsX3237DsafveVIxNNTpvtDV6rcveLO1uEOT7YbuMNiZjqtl4Xm7TdJ0Rkrap3i5WVf8lSfHv9EKOC5Dsql+xMybfbvFBdrYVuR+fOFbhPhHtHZ8bJzLoxoqnoFVx7Kck8xG7sZdlG1oYRmu38HnJ9eZLzIW1jCFvuV9gxxPZ3/IY2x0Z4SiNYR7zG/MEZmwPQvMTLVS7y2wCA7TrWSABBMVSk8VHNMiQCe3pisIGM/ALMeOjB6wPYxIDdJUg==","layer_level":3},{"id":"4ef7f039-bb4a-4467-a957-9d7d0b44f9db","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Trino配置","description":"trino-configuration","prompt":"创建Trino连接器配置文档,详细说明Trino连接参数配置,包括Coordinator地址、端口、目录名称、模式名称等核心参数。描述Trino认证配置方法,支持LDAP、Kerberos、JWT令牌等多种认证方式。说明SSL/TLS加密连接配置和证书管理。提供Trino连接的高级配置选项,如会话属性、查询超时设置、资源组配置等。包含Trino性能调优建议和连接测试方法。","parent_id":"860d9985-eb7d-432e-a1d2-69e59ae12cef","order":3,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoConnector.java,datavines-connector/datavines-connector-trino/src/main/java/io/datavines/connector/plugin/TrinoDataSourceInfo.java","gmt_create":"2025-12-25T23:46:48+08:00","gmt_modified":"2025-12-26T02:27:17+08:00","raw_data":"WikiEncrypted:FYrCoN4XmaUPZe9PhIdc4ceBlaaITMcNaaXQYxcnqO4ZYXlEjc7nw3rmx/eTd4pjLRviZZd3wp7Ucqox7JhYJJopgef+roGeYN27BsTxpPVy3xvPbYjRR8lRx/4qy1pbjNVlqrFy0gGXTYJGjSlytppKbO+KszrKEo7DUwiIwW3zK6v7DB+dMerJqfVGetR8m+HmsX4ye8SSEWH6fidqsLJRoXxDoY1Is0K+4MtY9/FsBH0sIPxncqqYa7hpmq5Um6fTrwFE/Rr3Lm/lvfiZbKs67f5xocvJMltokk12+LUof7oDi2NQm6Zt3v0ru49CFnY+XG7s7v0F5aJhnLJBhhmYJRFm5K//A73miE4jSrrr8G1W0RxtVjW9gG88N6NbXwoUtqY7MBkIg85+mhcTwt5UDLQ5tdrjv55GZbiDyiGtscLMmj+0GZrak68dKdHlgymofrWssuJ1KZOEYO45reeZ7YqCzBL9xdHq8vltgaLt6FQJlVVwiFNtvhn4ac+AxauZV36GgeWYFSMwlF6uaKNf3eENQx0lIOF7MfKoks9RsUvP5MhzN3gxiH/aaBKQrQWGUc9FEMqU9bUna7IoaRS2Sa05B+OzmHncyWoscHPSu03PosaCCylYfOujGqoE7GMNd4m1QcZlHpGqJB9w/llY3f78H6ByAtzrkaQkil/mJ1ETg5eCY/fFGyTKGnNDqSARhMTg14bR6Cdd87hkm+fIscFoCDqsHVD1sdTgp4+Z8MC8EeWaJmDedtCYBHeT5Zoomar/1A50DGdTce2QAt4zxbCkHPOBfsAd1OMDdgiALnZ/AF+fjC8oiqHr/POHDDIoTCfGGpks36pokbg3Y4VCSfFwRe9B+vkKVDMn/fGI38pcW2z1xFOI7ahY1HTdmFeCSoAqg2nD6ReC2Wtafi7XhXdFYhC8eFMd7ZwdBrbUxTQhOaLZglLQ+yvfEce0H0zB3d0GCCTK8b99JnlfHcETwkFCq4magI+D8AlhsG5TwaJUR8HhU8d77wyyFyESxdy9mLXmZ73/EYOrUhi73EBtzJ8tR5BPLgWz3jFIiWqo+X8gpTYHC5m0WzI4tTSNipycQp54LXxnim9m6v9TaIjdaX/fkrXmNvBqaynC1M5JLF7aQbYzuKsru2butQbOz0+7DxESx1/V9RxnziwxqJsdS/tEv+zYPqgfZyl/gkc=","layer_level":3},{"id":"90618369-350f-4168-9952-0af519aa0add","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"SQL Server配置","description":"sqlserver-configuration","prompt":"创建SQL Server连接器配置文档,详细说明SQL Server数据库的配置方法。包括JDBC连接字符串格式(jdbc:sqlserver://host:port;databaseName=database)、连接参数(如encrypt、trustServerCertificate、loginTimeout等)、SSL配置方法、连接池参数设置。解释SQL Server特有的配置选项,如Windows身份验证配置、AlwaysOn可用性组配置、多子网故障转移配置等。提供性能调优建议,如连接复用、批量操作、查询超时设置等。说明如何测试SQL Server连接器的连通性和性能。","parent_id":"82e5534e-5b78-4582-ba77-8590166e6cd0","order":3,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-sqlserver/src/main/java/io/datavines/connector/plugin/SqlServerConnector.java,datavines-connector/datavines-connector-sqlserver/src/main/java/io/datavines/connector/plugin/SqlServerDataSourceInfo.java,datavines-connector/datavines-connector-sqlserver/src/main/java/io/datavines/connector/plugin/SqlServerDialect.java","gmt_create":"2025-12-25T23:46:58+08:00","gmt_modified":"2025-12-26T02:28:36+08:00","raw_data":"WikiEncrypted:MJVCI5x4g/Qlzv+oH99PQncALVbZ4jRoYVRxr7lLSSIFyjqbiIxWEpu2L46+iam9kLjMvbdycHOZA/1SpKnc6nNTfKX+8z08sSyRKhODE75hMreO6yAxaWXWzsKN8T+CtXWovJKyWKRP2od3k3ju9X3XtoM9Jlh5QtRDgKzAeqsDRCukUxvkU8XiJounE1az4JP0HwpG81jkrA3gEkyYMlMYaxb5lJMsY5+ufez5KudlfROPmrQQsRzMx82fGu5RrBJwdnnc4a84MMsAK/kueecflAIKDzJCKSdNF9GvM5GQ8mncrEXICPD5aCwIT43Yg0bgARHyQb2eIXil4rOlCs5Bss1Jjh2NqVlok8X6UIdRzOvrkY3IMdHlJDIjtzxeLBuYIiUSEbxzRK0XshXzx5jHssB9tcct7w8FxNJneUjB/y8R8msXfT4zv9SI1Dsrh8usA5Koj9BQVpHEJ2TxWjqbQi6m5MxfBFnvWsfnlYbVuURTZcOE4Hd4To3vRuSDTd5UNGa9VZKEjk/9DvZbYrsaGUJhYTmSc6ojsCwimcTMUTNVB2L2n38dQ6AZNdExaqO6TPQ069Y2I5JBN8a+/2rWIMb/jr1Y28lefXPZ6XWmFxMApsrZBEsS3SZIlrFZWMx4+QJJr9Kwd0yURlAKrbQBFsIcA6SkwUCUrA7pnGZkGJHphXA3mBMFzqYmgR6SGUwaUmc19Cb8NVYLgp2HlBCUd5vxZupR3K9+WVi9uEpVVp/TtPT7gEipKF8CKapH1x4L5XSjC9Gm3j912/AtUmwM5wG8TMTEBlTtc0yAl/kl5EcCYmoVnmChSHQA+ll2JtmOTN+bDBJuCjfgbne5EQVnzMOEPk8b6EwScsdEzvSsx23TGuZmW6l5srp7vOt/JA3sOWvuymya6JJlBDoZChO5IDmN6KOS5RzCvJPIFrwP0hiswY/JV68CYWLSlm5BbFYeGlLNnxYi/T0023EZ1JmPLxPaES9oD1HeqFquJdgGwPjpSJSQy3XjHRZfYABD7PELLC8mI1V1w7ocB2UVgpgKKJDtw1k/V9rqRfXzi59iDGtHOn5mA0zSXugxNWlS7ciNd//7ctPqquCAzWsXvWvW1mOG8BkgEYzgOCvVacAoOLbUBX3bWkvHDMPbBxnOphNY9Efy4tFWoMH/gkw51wYfBrwA5Im7Brm4UEoqS0cpOnE5pQuStuEFq1Fj+N+gh6E2/ufPCgv6An5J3wa0KZF+BaYtJHGAV4hUs2rdYw2lY5H8+kH/93mGvNOhSpgX8oGFgxc+AaHQkbD4HqCO6A7bRfyyDh5E7Kj1ibP3fEZI/uuKfZtwK6rSHDFKCeF1QtagLhoKmoFEBTPbPjN+pdEUx/e3wdoLHaGaGk0X8VUXEXSApsGtI0ZeAvpANgrXTYH0tVHoWhd/hz/AlDjdV2ZTlkmy24r2+FWAS3cMex2oTAoCf10SQn8UY1nGEQMGLcIqmUS+kN0x+4jVbFLOcZWxglrzOgkOzl7QAtVGAdRoL1stv+P5QrgFpftf4LUJ","layer_level":3},{"id":"9805acb1-5a4e-431f-b588-628b8212df88","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"统计指标检查","description":"statistical-checks","prompt":"开发统计指标检查规则的详细文档。全面解析ColumnAvg、ColumnSum和ColumnStdDev等统计规则的计算逻辑和应用场景。深入分析其在数据质量监控中的作用,包括均值异常检测、总量核对和离散程度评估。详细说明浮点数精度处理、大数据量下的计算优化和分布式环境中的执行策略。提供行业应用案例和性能调优指南。","parent_id":"8195f94f-7c42-40f0-8e98-ab1163cac8ae","order":3,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnAvg.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnSum.java,datavines-metric/datavines-metric-plugins/src/main/java/io/datavines/metric/plugin/ColumnStdDev.java","gmt_create":"2025-12-25T23:47:36+08:00","gmt_modified":"2025-12-26T08:16:57+08:00","raw_data":"WikiEncrypted:pYjAeNwRencjUB2+jbOeage0AYnH3LjMQxJz1VbIQF5ZL7eci+PspuJi+hsoZeal4/T4g3gfKAQ5VSCWxIRTqKmrrM6YMuHbii3nIajyS0PrtJRAaRay9cYJ2y2Z/n1oWlmkGKiT0yEyCoiR74Oln8HE5u4jTqdaTZfPqMaCBsgvKdVH/FT9xdZTmnLAuNyuHTY35C68ylNP3uqPXDtuuXfIgYcXheINptRgANXfFK0JiQ+VmIskNWGghjpmNu2kXMbfqsXBi/YOEMznKTMRN1Z6Q7naSzn/oOzRTLGog2WQvuhhqKrX/d1cvngTokQ/7SlvBXWNLFhHiCH2TP2K/9v2SDzgTA2kMtG5oKq5Wz3tC584MiQraWCG9mxuWSyis6XEt1HSzJmFOXm8oVSn+YElhafzRo8fmwo96s0pc0Ck8CnMOgNuTsS8pXbmRZDc36LWm9Qv2I3uHcSJUJFTLqV6vsKt3/DJNyxV11JJ/zfLUW7DUV31dLKZHViJTptl9Tl6cW3lvQKXglE9rW0PxZcm3zhMocmRL1DuAb7ysUkJe+A5D9UHQAI+Wmfi+YAO81Zh2ctYPAcd+ptowYEJ+j0nO7DjXN1uxj4uJiwPdfKX3XZEydv2UEAj8D6ZNO2ciQhy5L6rU//2kiejjHbRiXJ2vUA57D1IbQ72h3MK8vhBHtUFdYQpXpXLjNxl7tjO7zq8sx9OFOl2qxcdCXS4MCDi0qxNTrcuS3Jj8QoeBnu2OyCSIAaCbZM8CHoIinxRlfzBFeMY2QKtg4rlLVtio1o8XMc9vumwdTUnYxHm48FLGH2lWZnnPsuU5LCPeNVNadt99lJgaw4Rp7fl5BplLhO1Woz/KMjJwe74IJRJMPXzRrGTlOT6ik5ReFuVgp9amAlAXf3RYJU5y8QdQ3Go4f0cmHZi0e7XqreQPUkNH6bQnW+cno/K7BvEwIGoW+4g8eJYN/EckyjvIbkjA2u3MJ1XOsN6FsXdYU1IhMFRtJu5/L0Nn038SRVFSrEL6ZDoagRvkDnuMRJTXkPhrnptpBCbYItRc4BeW/M3ZjYz4J9zF2omQ5Q/XPXiYUtg0h5V26Haq0tZiV5s4zDqbm+xfjaIEeFsMeJE0OBXTpJBCFBufc+lRFYtAZ4fk5oOT6q7q9T4uW9BqYTvaz9rYBbZAXJoTxnudcg4DchEe29IHvo7WYhsY2Ow+4QUodKkt1OSPV2CfUc9Ook0w02e8oIH5huk3MVPaIMNZnX3y0a51mA=","layer_level":4},{"id":"ba0be7d5-aa3d-429f-8967-cbbbe9a92afa","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"最近N天平均值策略","description":"last-n-day-avg-strategy","prompt":"创建最近N天平均值预期值策略的详细文档。深入分析Last7DayAvg、Last30DayAvg及其Spark实现类的计算逻辑,解释滑动时间窗口的处理机制。详细说明不同时间跨度(7天、30天)的配置方法、性能优化策略和历史数据查询优化。提供在短期趋势分析中的应用案例,如最近7天网站访问量监控。讨论数据新鲜度、窗口滑动频率对监控效果的影响。","parent_id":"489baeb5-14c4-4d03-b73b-be142d956487","order":3,"progress_status":"completed","dependent_files":"datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/Last7DayAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/Last30DayAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/SparkLast7DayAvg.java,datavines-metric/datavines-metric-expected-plugins/src/main/java/io/datavines/metric/expected/plugin/SparkLast30DayAvg.java","gmt_create":"2025-12-25T23:47:37+08:00","gmt_modified":"2025-12-26T08:18:41+08:00","raw_data":"WikiEncrypted:uJHBFAgNmOQBb/ROgdX8HT1zSmnubaxURjDFhDHOJg2Wd6IeHzRpdVYLn0jTPSiqpcUX1sQnWl+vZZGNQWLiI3l+ZZd/EBRJHFjhbPs+JKJCu4+7foOFnKl5FebLyGsglnXtVyMdmowP2O6rfOgNfFTKG3L2dWca4aEfnVBpmPqEvjnQDvJsAoMczq4a5q3w++ik/EcH0CzM/YFeTxNwy9xVZJKWcnfpm5Pk9slV0vXXEt9DiEKAFdiZhVzvD1ynC5pamUx1Lybml182jJtrGCkeCuhUFNX8lcKtwRrIgWTFDsK9LrUPLyDWR0MPrXNyJHcf0nkGcG0PrJlGFraAcq1+ZU2BhI0+tjkNN0P1ZVzKFQlQFeiAUH1Y6havxO08GFW89nuPP4FRLeuptywS/qVcLe2Du/D4MhKuTdaKRM2hobqBboo72G56PwT/UeawOafdMVFzjV3nJY6R9SaiY+Gi/JFoC25tbt5kvAnqqRA0R5dir4kc77OySUO3l8fAcJdev1q1KzcaxMFq+Ynqxmbp9pDUXaNR0UXAg1Bf6THb2Lc82/ocB5fMri4JGjFJNWAO0K4mR/MQHTzQvAqZNGXmQyRuUI1KK7R1o9KefY/DMaWsv14+5AztbX+52TY4nU93A8xmprMNp5wFrNx0aMAu0yG54QPCL3jgFLopCqHzqM45uvYQF6mUG3P4+a0SbIdXUQiuMy0D2mnqguWDb3fAtSLZCwTJXijsjZ7GCff7Wg6UliWW+e8/kIKFwDYqfvPOoR8b61GHu/tUwWJ79cnP9o8lIeKW6hIVcaMGRff9iHE9xEDriwkVNoB6uoPBLMVTa/XVSlt1S1611rVe01SsBrMzHIYw0BFPDSujQnYIsdw+OO/1HdM5tvHxQJItT/1RE1Rq6qNHS3O0axLRThY/0DjR3O7jj+iCPNZqo4KtQ015wvipWssfUo3TDc/2Qpamrd9ekeZctPU8cejSEhM1228bojpG+g3N/mch2RS0qTPEERaBevocnttS2A2k0G9oGkkdxhCQFj/baTkDYPkTpcEVvzO4bgQjvqPLUwATXyNluCyJbGWZuJV3hjUSCdVippNS9r2vqwHTEFByhnFhG7r+mDAEE2GLJ76z6gwgECECX71SeYq/1N3QKQP4PWBGoGybek7PGwmJE+jpBHECBlC47DMxFQi/yfEhslrMMbRpqyEjiOODBHor3D74WxeSgiZHdrkfym+zaNdt2qge0t2JTs6JP+lJkaKl8GA/ozb0SmFLTOKxSSxa7VYWh8S3fhPRQUL0gRLUlFKDYwBlQ1GAykUdlizlKp3Hxuy5r+FulpElQo0KpfBY1OP/olkzjo0XVqDBSBVa8m0IKZXZeY6PbaOKRR9GTZ7SmJB8qMJZ2IHcAIaQAQwHugETlBDTCuw3pyFG4VieYkWjOxfShhWQkT1yNI9Q1FBOEi7q8QiRu1PewsBjaTjyfY1IS8MmABNsdJrHCwgnTLEaP6c24mtqe+ds+izOQOr3QdUPEjeE5AO7ph5naJbz6C05WPKisTQbzwfNzz1DayZKt95phfBRcgM7tJESTEzBpag=","layer_level":4},{"id":"c391a73d-20a9-4e3e-b13d-54fba38ef59d","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"模块详解","description":"module-details","prompt":"创建模块详解文档,深入分析DataVines的各个功能模块。为每个模块提供详细的介绍,包括其职责、接口、配置和使用方法。重点分析server、engine、connector、metric、notification、registry和ui等核心模块。解释每个模块的内部结构和关键类的作用。提供模块间的依赖关系和集成方式。包含模块配置的最佳实践和性能优化建议。为开发者提供模块扩展和定制的指导。","order":4,"progress_status":"completed","dependent_files":"datavines-server/pom.xml,datavines-engine/pom.xml,datavines-connector/pom.xml,datavines-metric/pom.xml,datavines-notification/pom.xml,datavines-registry/pom.xml,datavines-ui/pom.xml","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-25T23:51:04+08:00","raw_data":"WikiEncrypted:MaEDad3+dpW6rLlXdYaTGW/i3OHTJULqGjgc3N3bJFdti7othFqv4GVPodx+BBRRNfPAjWi0t7kqeNChCy+omc3/ZLpWDITYgsMpnaEIm6OHD0jcgbZ7cMYkCtMafV6Xv2c83tvKqV7Y58mMSUCyo919jeNOXDNVA/r5kur43c1rrJ3dKJiOga7iD6eAVg7Vg8oRWI9C6+AoDsWMNrMGcCYQsHX3up5N4/tEed03sXUUAYWwMxxVeyz3HYWlL6BTBOqamQscBDAqNzbLrn1ZaZbhUVaRBYCUmH8EFjNLacZS8RD4VjKYY2vzOOdlI31jWH5X/9Cq5LnONc0BgbfPpc2ZqE70fpD6YVVPRYGHf7z8jl7dHD0/afFWhSetPCkAZEx5H2Q+rJaISvRkkaFL/7JGebE/iPa5YkmRD12w65/QyVuwT0wzSgo4GrNUnxr8i+ulY2P5p21LK9ldO2BvgwC0OFQdqw5m1ybeH7S4WrJ8TiQD+7BRUO+let7h0xkHwqyGaBypX/Uo11WebEmqKZoG1Tky7YT9mrvaYlY+p+uknLC80Nj+/o0ufawBb9uA0fw7U6o4tcRspaHp+VndVqGspnXo2Dwdy2CBYeUTa6BtpnfGIXAGuZVVebk5T7fnxhCzFwh2fft2iQqwnsylD7JcMus9TrpRxZDtFmdybq4rBPchRJ2VetHmj62Y0zM3XxxxIHyX0gQRbqzM3IPa14BwtgEitLEyPe5HMOCK5/L4jvvXWdQiRylunq+IzlVxGlZhwK3n2uy72f4EOIPuIYOg7Ey4omD9BHB+zf7uPXsSRnMq2TN+5yHlVb06wIqRIQ3x71DkhmgaKCreSV2u4HVA8jpTcNB4fhB8HoRtaMDYzO3/DcyfLCfW/xn29mQmKOa8apm8A9jnJmXNim2m/C0o2THYe52Pkai23bUCBBlzs7pq5U7qu9bu1XjU5bqAOXBgGndJP+jrgBpTQz/UmgbtQOMvgpQAPy2NBKpTxpOMaMS1nljn82cRlalFbOG7mJU/+K82lnQJIxNROYYGXAXHnfqZdLjpxqqBkSipyc1LmScJvwt9M/FnEtG9GzJvyhyIkhbStk1vNx/WzpU020JkTzqt5CkM00zG6tkl9sr1JM9wrGdyqL2uqke81Pp3LTyIu60m+cp+dF2Smed+lQ=="},{"id":"da4c595f-1508-456b-b54f-fd0b5324fa43","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"注册中心机制","description":"registry-mechanism","prompt":"创建DataVines注册中心机制文档,详细描述服务注册与发现架构。解释Registry接口的设计原理和实现方式,包括ZooKeeper和MySQL两种实现。分析服务实例的注册、心跳检测和故障剔除机制。描述RegistryHolder如何管理注册中心客户端实例。说明分布式锁的实现原理和应用场景。提供注册中心选型建议和性能优化方案。","parent_id":"401be447-6b3e-436c-8d7e-a0845a921e20","order":4,"progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java,datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java,datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java,datavines-server/src/main/java/io/datavines/server/registry/RegistryHolder.java","gmt_create":"2025-12-25T23:41:09+08:00","gmt_modified":"2025-12-26T00:29:25+08:00","raw_data":"WikiEncrypted:hvwFz+sIainc/WWi9rXmKV+lDR+knS/XI/IjB9qIEF2oA/BKUQFcbXe1cdl/5QVYh5WM38v4lDCN2UKtHJJBgw4ypUXeXUAPKKyqlBh6WLhtIlcmvDHkNptlGLNKxwsyt3Ru8IRNCsCx5B5GBMpEwFa9SS6cduNmavurjQ7tSQb/M413y++5RHic5/YEB6BtiIeF8XIWJ2VzMDID48R5dWU2Rzz3YYoVaTAA9Ff/IY2TaLYIWbmzSE6IndRGDXo7lWqhs1r7085uP4aOiRsFCMKsQ8+kBA+XJx4X8XZO6oFZjT2uqu5OwvzhjNuT+PjXY2+7YRn2Yrtg/BDuKhMrNDP/hgYQv/iDdapgMwZ6eFU3AmkQFDaZodF8+xmQA/Z0nHFUHlyoEgk3GqrvpIkzaGyDZTTFG3kXwZYHyX37n9jMrnpngy2/My8fBAUITTxLoRVVyIoFh+57MvsAxZflsNCK0cHVmlwIRCy+13ElqHBT/nEiJuQhF7GOQ/Krcd3SmQYbbh7IJ1GdjbOskHk3ZUq0S4jBKJ6lmrOy1r+6HX6+nRXJ32kgNfLgRc1qxK+XqB07paMrn+8VCsUlEgj9pAYNYKqmOlxI1z1gLZACPNhdRA3R+RR0dcLvDCS4PGdh3rVHmLXC8OjeahfeLmeVuwsOnD3Pfq6UCvxtEv85wqUhFVd2WYjM707BpSZmADSCNRgO7MjqkNTxNRLqX/JrnD4nkPvF0saMF/tV6qBOBYFioafBQHS+NYteb/BOCaWghhjp5bpw9Ad3w5v2m5+y1zfDWRahjH22R9SgTHUCKdP3GiAHe2Y7MMogJpDKEwmaysX45xE3ZtD+EwZM0f374e3n0HMtP45xqfoCVYBprWdLog9yoqr/J6Yks9mUcgiWxZFw3LGzDzVA9e/JktPALik0TA3br3jpFUgHwLCmBD+XVmcRYVU9bET3bcZQuys0rFDRPftOB8WUQJ0dBZpaUgwplyk6iZAMKN0l6cMs8jsqaG99khMmVWNbIGGatQthKcfSEFk41xvXmgiQeom081yvU3JrCT6CkiTK5JIJdqLaF7DoLUKeER+O+LHWGSZLU1N84M2DUJIfKt+1yiagzLCGgRNU2iG5zGqWbP0Jt7nwRuRxYI7AXn6NCHsyXou/3cj1FCVoYz3v1V1Yd08pD0F5J11piPFeWbc0AzzeQcDsRJ+pWXwQ7EOW3sVYxqtBpc6aT9gmqf3hFwh5jlD9dX/MHljxjnMrvDifNXwlAQaij9PoGKfXBWpOSdL4VwvoGt/GYTcg0YZ1iXzItQnA2P8kyxosaa6iELM6WUv+2lz6VnPbq4UdaCiwAZuWE6RSFi36hnWM2aH6/XcMuEAPQ2ceJI0TGNvru92Dsk6NDvArQUk9HIWUEiONUnTXD9q8sMk6g/Xb71otcoYHGj5MVBAPJaGfKWh0OnsJoMMGtX1utNVBVL7GT5k0pz89eM4Tjk55mCI1sxeRmkcRcCpZlg==","layer_level":1},{"id":"9b0e5495-2217-4011-bc46-1d550de3afd9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"datavines-notification模块","description":"notification-module","prompt":"创建datavines-notification模块的详细文档。解释该模块作为告警系统的功能,包括钉钉、企业微信、邮件等多种通知渠道的集成。详细描述SLA(服务等级协议)的配置、触发条件和通知策略。分析通知插件的SPI机制和扩展方式。提供自定义通知渠道的开发指南和消息模板配置。包含通知可靠性保证、重试机制和性能优化建议。","parent_id":"c391a73d-20a9-4e3e-b13d-54fba38ef59d","order":4,"progress_status":"completed","dependent_files":"datavines-notification/datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java,datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java,datavines-notification/datavines-notification-plugin-dingtalk/src/main/java/io/datavines/notification/plugin/dingtalk/DingTalkSlasHandlerPlugin.java,datavines-notification/datavines-notification-plugin-email/src/main/java/io/datavines/notification/plugin/email/EmailSlasHandlerPlugin.java","gmt_create":"2025-12-25T23:41:22+08:00","gmt_modified":"2025-12-26T00:29:27+08:00","raw_data":"WikiEncrypted:4+tXcquKioWk6hL5AaAVvYThkRONQIxvWjlKJx+2INHAHqHAmLxqC2yJgPVImdn94//rUbY3oqqg72M+ANNjVwhQGNEBRBs5F/jICRc5EFCnEKmN3gh0VtDJ7eQQSI09pBkulAxbxhqmiIB4iS3Ml6cYs1GGMwT0jxiMQUtYWNKKgZsK0uSGs2bPYty6Prb9lgU8xDYL0xLAkyyDRhdiQS/ylDTGmUeVxclx1ZykClsqoAIefJ6NES/azrk5/8+QdYaVSX5m89IiugW18zGZ7ymc2thMdHqLOV7PGgUH2h5HKzZUKsq1WY9DwBDanBQaZ8Km6wuFtqeYtLOFYzACwbc5wxP+kogYnXnBNzFPeICrPSH7bs8j0Yrs+TFhT+61IHkAbQXMuD808CfbQD9PkV6EJ8+KEOJVx14ja0whJF5Sv4wYOt9lCgq4L9MCAJCLvXlphlVzFsBdOfIqmDZlOzx2DnijcIOstkTmguy5RahQYOGM9l/FLml3w09ttQx9z7bRYaWs8Kj2S1kGqlP2Ha7o9ceiu0W0lHyhu3c7yZ5TXh3I0buYxZ7Z2lk5F5tdfiPBRTRm0wEyjyfargmPGmMkcVh9PSTa/18HApNlpTLRRv/n1jJuvM6TH9SWVjuXsBSTz5yMBDaNhbWY7sOAc4PLA3ZOzO4aSOW5jFIWWRsmDYhGyHMGyTnYqBm/tebd/U0tyhwQ7y5UskXfTacNRc8nJgIY3lM45d/rxx1mgRmU/kx9G9EvXMq/WxQCb4cuVVL8b73PfFx5G5NdcY+kCXH/8Gsqt8OCTUBV/+m+EznOiGG/jk0XC1FIwrVCgiNFkiU0KtVHu3yFsE9dzUHxPHk7U6HmPDZcK1tZdGskL+Tri3CFVOemD2wwGNZYWMm7lshN+2IP7ZKPzse0etkUi6ID/6csIr8zN1IhdIUHhSNkmqhrq0RlMJ6C//ZfcVx20F/jVNWYx2cvpmvjwIZpo/Jyx1QK5HIGoNB9px6GMoOfcHXvrwPI5631M18OHNufXHQD0G96f+TVoBFEE0IQs1MVOoTvZwVlQXIa8y392zflP1spQ5tNbOn6yIzbb3BRZhKKA70/ZrjI71UXMFRUu/AVo4paYw6m8lMUnytThiPPHlF6IKQHfKV+jB6fdUcWg5CClxVyziRjMhpArGWcxnFtniXKzP+Z9WevvpTCromlm4aLmOpXM3jDBWIIrNWQXbt6ErxeErck76XkCiimsjvr+76DP/Wq95MQqPr1Jv7OfKbxnUfNyII+onLJ36Uhux5lTkgB1S7D9CNHjC7ZHG2VBon/qmkyZ90j5bMLCwrQfbkDl6D0hYqKrN6+m/gkXZoN81QOHyipDgPkiKNfgVxmzrjcULBwp9RA0OXi04izM1Iw6euoR3166xajZc6fU7LkCd/xITK3/AMKPQ+c4S0dsKFe8W3+IbPnxa2GOZxsWhBkkaX9dgvLT+5s/Qn6iD5bsDuIJzuJe8V2Pe+qQmhAmOosX0Bbqa5EkV17xUc8RaewNPnhiDjQwmUM8Gp3lQNP1fvVJq1vnLFhjaMx0vJA5e6C8dOv5EekFGWd2DhZkSsGi480u2i0YvV+PVmr","layer_level":1},{"id":"22e9964c-dd6d-4985-afe0-8695518abc55","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"注册中心插件开发","description":"registry-plugin","prompt":"开发注册中心插件开发指南,详细介绍如何为DataVines开发新的注册中心插件。解释Registry接口的核心功能和实现要求,包括服务注册、发现和监听机制。提供ZooKeeper和MySQL注册中心的实现示例,展示如何处理节点管理、会话维护和故障转移。涵盖分布式锁的实现和服务器状态管理。指导开发者如何实现连接状态监听和事件通知。包含性能优化建议和高可用性设计考虑。","parent_id":"f7482163-91b0-43ed-b702-cebf50029b91","order":4,"progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java,datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java,datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java,datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/SubscribeListener.java,datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/ConnectionListener.java","gmt_create":"2025-12-25T23:41:31+08:00","gmt_modified":"2025-12-26T00:29:48+08:00","raw_data":"WikiEncrypted:hvwFz+sIainc/WWi9rXmKQOh2YmMDqqOtso6wyOpEvAb3Ei/gchOkQlB77EaCtXgQ/oVJfVRs9SyK+9u+NUVhbnkLq4QTfOiLB15sndGnOTIRo8iyHv1lKOTpDQlm0wY6Y46tNIpLKQB55XLor6f69l9boVXa+H75LuxJY/4zAG3tSWBNn/KdicmID6g08I+xu7+Kp/ePZ+ruO9eZ5PT6SBwHli4XgRTtclnVDVFqdQhCwiT+Rh4Oa0VZy4QiHpKm/aFVGHQOPYGZAv40qtvlf0ttH0xAHha55Ei9HU9gWoRiInVuYLnCOt0eu3VnILw9qqIdwWr5F9epAidWja4Hq9kK+NKvqogAlXbvDsBefsGtIeRy/KQYFBLhu6yLX4gruEVc+AydSrQKthFHgVWszFq1QSJw4v9TjFgK7k25f8I2BSq6e7pDD/YxwdbT0nOuaYQCrJUfsVPYrOp74Be8YO3ZdTfQVJrRXRZf/z4jYt3fyocIZHgY3N+nlwKbqWVAv+kLs4XkY8sRzyK9JjbVogpw/Vm6kzVOp1ekusi0kB6ia5FF1y7VqhJepfHCoT7hcA69jxzCzScKhtjPB077ehRn2p/o4pgBah8nvKWwt26MKKyNuflZcc/+B0gZgUH/YyO+aeMX4+R+l2A1NuUQg1nKHojCWMlcM22yV+maw7h7aw6BHy++bLWluyXS2hVFVexquzfAH8Ms5PgaaCOJvC3qipopBlhDG5dz0e7ra8fX7JPVmAeHcjrYqU6/V3Jy6ZOBKAL1W3lnnIJc78z11K3VOGyayO1sEl8g173wP98K1iByUKOdG3NRUgQ0ADfgX2z+t9TC8ZlBYfivbYDco1Wq/Xng+zLkitMcrodqoBtQuaLZFcUJ+F3aa2/OUay0Nk8Kj70mDmI92ZbBIsysYDEERMOJYMPw5SsiY292RPbGHUCj3CQa1Z4lRvvNc4WSOE0JMlPS3NhAIe0sUHK31mkapJplDAxr86gAcXrCHi8y2orwMd6wgs1bA2G7s4F3ngkJr1iVw+sjH/AInRiTk7hx/DZ8dUYpkFvatkp5IbmoTEE0gf7Uay13HelKm8yrALtKCNc1R+EfOk2Dy/TV1VQFRztZKebRW77WL4gCMQaZhHEJEE7CWD0rr5dwHa7pZMYyNVlkWBAVOFiyeHb2YDAtoVAlLVW2DPPC0R8yZsdBF0XokHr6ZOtMN9UCuGWJ6dnu5sqUa/XtNq/PsrrX6gF8gMVjd8SiUVPyjPMfIRiqDEo9w79naFL0qX8yscO4WZQeQ1u6YXu0SUHlP4FdM5rbMbVJnEHEmqRvNJX09Y5tqprsd2AtGhXMASX2lXTV7ScVEYQrvJDqM6b3eZ+FDvwPYlhR2YqA2VOY88uuFnyusth3aFI9mNZwFKUshDBmeoQiDxf2HY1/kMV3QWjpj9ADOFXehTLwC1K7FxWY6lXTanSGKiC7b1wJatkqiyt4ZH2DCa5ehu3vqSVikvyTybc8ebe7CfmZtEPeZA5mhx4Dy0o44TcQB/T5GfhREjhsU7qbdajGnRqrL8LD+BijL7DoWNLCXqMbPbT3UzCx1a4f2k06DNmjGm1mALFNcjy+UCz1K2nPfo9SZjVhdbNpHmvY69UwPSJ/Qfs6X/nFvFg/2Jy+S3evPuOelOpDMyPxti2Mw1Kp2DKb26JG4OD7u6n5UzhMvBr75EfKoK3AMrU7Vfyf78pjejwuYso6Ef5kgSpiwhzci75IMuhynThfmUK/huTr4YGiwNRkzSUK/U=","layer_level":1},{"id":"6b9ad9ae-0d2b-4fb5-bc4f-63f4901c317a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"工作空间API","description":"workspace-api","prompt":"创建工作空间API的详细文档,全面记录与工作空间管理相关的所有RESTful接口。详细描述创建、更新、删除工作空间以及管理用户与工作空间关系的API端点。文档化工作空间配置的JSON结构,包括名称、描述、成员管理等。解释工作空间隔离机制和资源分配策略。提供批量用户管理、权限分配等高级功能的API使用方法。包含工作空间配额管理和审计日志相关的API说明。为多租户场景下的API使用提供指导。","parent_id":"b4082be3-2f3e-42dd-89fa-9295da3c62a6","order":4,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java,datavines-server/src/main/java/io/datavines/server/api/dto/workspace/WorkSpaceCreate.java,datavines-server/src/main/java/io/datavines/server/api/dto/workspace/WorkSpaceUpdate.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/WorkSpaceVO.java","gmt_create":"2025-12-25T23:41:32+08:00","gmt_modified":"2025-12-26T00:30:46+08:00","raw_data":"WikiEncrypted:Di1ozXFlWwX2EdovvmvRIs6TY4bcbnCnzDnMEUjqyqlysJtQTlGbfT5WeZ/inL3dMK8h1fNU0fkR3eRUUy0oGYuyst77dV+oswb75UguRM9lx2S/GcQWVVzZczjvRRRt4hbqPb0y5cDQYOePrVp73CVhfo/R32mXoL7C5k+f1Z75bwK3AZUIxJFWqq7LfsL9iermeS+I69V8k9U2mGFI1MxnlqGs3/KRlKB/0/5r1uF9MElQG98ka3BYRT40hZ+2kgBNMWohjg+4tFO/VYwVMjyFvk3wXLjRnYCdx1KXU+QMphbzeHBpihgam+08ptq9+MwWMQLl71VzTlBgiyJMb2++YfQLZKiRIZo7kiqIuTwi+JppAAQlI8FdXpioxpd5/y/TUNE0pbaAebMwnzrdyeQB8roHkz7bVmuVjkG4rcxUr9WdPmleT76ZdcwCNQJ3q5stzHBanqbxF2OjDi+mTDHwf70dTFWk0LCympX2d1DgVNFzPW/mHgM4Z/Rq/vGh187xU+qRrhFD+BlNECMygeKvMOFuyiwntDL/eCiDTAk6MX1IUy/p3qcwFy6EXLShmoJ5zSC2gD5sbwtqqLA9fk/B17mCWSZHR6ABMVYi0iAhVM1w0i+QTJxTqNk/Mi8MOZS9vcWEFmeW58TdYT7sEezRP8usqRNxGIAiRzs8TPbsQSTYH4lVNktM7A3cJfjdYcdLJIJ59qhI5wIOu5AGeS/wV11mhVY41oJs+nZZ1Mfpvv4cwCFtlN7rOafGGL8S+ojRjtPp3q0TXmrYuyd9pjVTKpq97azjTz8YCpXlsnb0b3h0uy4rLnCbbEB7kHbXm6ZgcUIps4bSZqTeifo/zFFz7iqlfzi7y4RYKZM7gAKsRwPh+Z+Z4y7aAh0Uf0cv7bzOLtvl2POk+Y7D6RstKAYmXI6JgbgaumqbeiyMiSr7rdtEheRRCmJap/eFWf2TM0VZepD7Qgy4miMoX9uLXt0cHyx108MnVNtt+DZ7xwmvURl04aYtXD6qo96h8Inep71oobX6cdniXRpDIKwfAW4sryK7xScRMCRGQSlnh+/e7xR8FravuqoclWTeCB5dxhb0VQWkRQ8RbQkEZ8pPIZn3c20xt5yiPbcSvtO6bsOD2Imzl0uAB0d+8FfPmal40AOkMsWGJR9P7Xbr3qdnrLJAYcWTJ2Cdv/DJ1dH4yG/d1GUAaKqYy3AqMcjwYSJTIw2NmIIHr5FjpS0AkUou6NbVReF7iEPHu/dvA+jdDZM1CS7/iK8kCyiY57hSeNPd5Ibqcn0JXgCT0+KT9kl4lalb8ShrgJOqP4l0GEzHhq8KeIPK9DDvLOFlON9K4dkpOaPoS/ZZTac7GB3TybneCQ/p82UGQdOTwCb3hI5EMCwQ/B8TsryvZfusSD8+bVZ/kjALy/iPE+WmXmpd9Q7oWF4udeZejYJMB3Ser3QzBewne8sRBB6smK3KTtXZ2NltvuY3yNSrfmMluEC7C2j0/UA7pPVYMEoYAswQy16jZmcqsyz8SLm/kBSKJHzxs11VeBfic10loNhjn9zRSHxNYISZ5pLEVjPoTAaBgBZtZHQ=","layer_level":1},{"id":"b9bd5add-71cf-428d-bd70-babc4f2ae67e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据生命周期","description":"data-lifecycle","prompt":"文档化DataVines中关键数据的生命周期管理策略。详细描述任务执行记录、执行结果等数据的创建、更新、归档和删除流程。解释数据保留策略的设计考虑,如为什么选择特定的保留期限。提供数据归档和清理的自动化脚本或配置。文档化数据版本管理策略,特别是在数据库模式变更时的数据迁移方法。包含数据备份和恢复方案,确保数据安全性和业务连续性。","parent_id":"1a586877-260a-4728-a2fa-ba930f91fad6","order":4,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java,datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecutionResult.java","gmt_create":"2025-12-25T23:41:51+08:00","gmt_modified":"2025-12-26T00:31:02+08:00","raw_data":"WikiEncrypted:WUqMXEcJKIYjwvMXzVIDok6G04cAMWoZAVMtfLbCNK1WfFt4IxhRQaYrRyPXN+5kjgwrCbo4rs97RKVE5uBTgdRnfHT32LpfF4dnCmTOaBpJ9jI4dVb3tv2tmtuYzW9XNivtwlQbMRdfQ4Y6wpP5e28V9nJuRPqRfv7GNR3FpXnHbelIHUfjKG4DuzoaBTqUuG9PbONNtYLyD/AWBG+r1yzU+QH0qYcrp/TNHpahEHTwxLdbTGeEf7JEyWUVv+jPWalskHyWPxxHILEj4tKg3C0zasAtRVnoiMD3imA9JVO/woSzG/bKAWTZNitlxKUu7xcfYKzXbFaue8Wuvio8tL0tf+qayOCv/wJX+AdaP86g01+aBldN+u4LX9NuiUt2+zZ0lxS12tZgbCv3UH+LNPQaf58nQovPefFamD8f5vIa317HwB5VUj17Pfd+WhbXlPseCL4a92/Ci/H5gwxREchkDsmW/zWLeFkn+E4M/xXCdyaYDMkgXk+bUQSOaDpkxL12WIKkbWPihMU0U7HXOcCgnoUjWdkI9APa34X29k7sglZpb0KVOts4tmIGIo2XMJ7Ohm2f6GbVMZ/Eq4Rm4nvTF6k+uKbvfnDpd8ex6PhOcMjCsPvzQU4zMFYU30I0z9KbnbTgANrWLPpcyIsEPgLp4VwHB7bYHjVmdYaw+umbTR4XjegDt7hu9SBrhAou21vY7WZ6oLEooFmzzOxPNk84VuPXjetf0YnpYgrTPz+Vtg9HVYbVo/uobMZojJ8SPCRP1aGibWiHI0E7ERv/j3z0TIPXqrZ+Gl5R3m8m5xTfMI9suSBlYw2m6LQKM8sDublMsGKjQiWARlCToEMG1mi5JBevdIzPomQvAqLhkbO6gUAJp6kBkU5ZM84dnBr8Dg8fpZfVO275v9v5VmNHSEmZYwpFJLyRBqqA/4/lG2Cd2kbICMLz+RdZ2Qj7VSNIMRHlM8TpIbLggXVqdWCg0zSlbHn+3EdEe/QK/JB+b06/7EhKAJ+mr6JliaNbaBgDuET+jFvv0qAPahm64OOaqH5cxxxpmWbNwHyYoPuu8iHwpeyOKY1S6CKSZXXWPD0lZUOio8s/lpQHS1+EK67uaCaYX4DmU8LRvng9BOPHeRcw1PUM6cHr4QxoPEc+cDPyZUfU7WuhX60CfdaBsQPJwosmr5koO8t7aOvmd+we34ssi0lLK69Q5JZqJysQSK3MiM0ImRcxIssyLSdAGf1BCnlZLf/UAx2oqqf6oonWHuo=","layer_level":1},{"id":"3268b632-dada-4561-a9f6-4ae317e64f29","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"连接器配置","description":"connector-configuration","prompt":"创建连接器配置文档,详细说明DataVines支持的各种数据源连接器(如MySQL、PostgreSQL、Oracle、SQL Server、Hive、Spark、Flink等)的配置方法。包括连接参数、认证方式、连接池配置、超时设置等。解释如何配置JDBC连接字符串、Kerberos认证等高级选项。提供连接器性能调优建议,如连接复用、批量操作等。说明如何开发和集成自定义连接器,以及如何测试连接器的连通性。","parent_id":"5d2798df-80b4-4ceb-b66b-9167054fa556","order":4,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java,datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java,datavines-connector/datavines-connector-jdbc/src/main/java/io/datavines/connector/plugin/JdbcConnector.java,datavines-connector/datavines-connector-mysql/src/main/java/io/datavines/connector/plugin/MysqlConnector.java,datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java","gmt_create":"2025-12-25T23:42:01+08:00","gmt_modified":"2026-01-29T21:48:29.3082543+08:00","raw_data":"WikiEncrypted:55dsYIZBuRDY/jem5TMYGtIoY55aDzl2Ggd7kdRiIlrkJnBm0Jgyd2Um7yd7k5YPVjF2w6T2DV6iMhU+LC66Tk8I6qqilTExgtcVgnoj1fe/eopZ0supXu7haZ9b7I951jH/CMsVWzBY2MfnMdwSMicDFVY5AUMUn4WPTU28lRWoKGLvR6IGAJaA6qGhvQfJ5nLDLGQ+N5nnMESVVDIWhxkOx4Q1Ay2ac6Mu6nvG4yY8Yq9TfG0g6IVXg2NVDVhZCzI/cZcBtCMaTUAuOpaBBm2DFGtkNCeLDteyf4CcKIaKsPg/qfIncjwxsTlir4ra39/9gveSwk2J6krNBIWFZz2x9dSuvjc8uh3Zo0smzQhrSwt6e7xi0w+pLJf9KljgdRBLFeO41CHoZQfkBluKozIY2pC1AtiaxkPLdA3Bduw0Qb3HzxUYxLBJsA0oa5gMat3lFFaffXvc3BuxkM8Jxm0/oQoVEnn89LER+WO46Vi+JAx8STwk9rUCwYJ9rHnreJKOfFCXFDCxzvUTtX3+j5LVRP8LqcAbROw26J0fABgs7RW1OF9U0fYOFNCTKnP1ON9hP1/jHVP1cEKg9vDwJHVRpvYtYL9dbNlGlAg3Ugy8xjf3oqzj9jgtktaoPW238/BcwfeCcfIfHoiuyDs/JwUB+YKzt2QmJytiaxCNBG/cadlP3mFS8+gMjGExmvNFNXOC9aPzc76LeSmvJ17o2WopMQiPdv4t+gUnE/rzkD9oyKc8SLzkKGMcofQ1zjP/MEG5IMelaisMFqs3g3vOqTCOzEA+xC1vItVFiJIn7f664LIk4shNaT5PgVLzxpE7bjMpjkRXfsndYwxBsKRAE8ehDuy85/cHqp33WkQMrcxdpLkbG2usvS8caq2KPyTHZwj8W56nUQmvpdzV7MxRkmwk4u8+dkZO8mtwpdZynShBt96rcXIjP9QEUvEFOBb5PLlHtVVM8mr/cGhoBMElNUVKrlPbDQHtpfvgb7a8J4nZtGI6L0GSJgU5T/+NRzq578rYmpflhLFETMzAtJbQVbLsCgFwSgbNzuQQ1Lpgt4p2bO4+a+q6ZRIrIh5dXYVnakIIULyDsex/4aZu8+TlGozPCdQ5TvVJdgKtTI710AvHlV3hoaoo1EocGhOCk08Uy2juKw2cm60+0GJBsh8hFVg/rkOj49tB1UMTLYBnoM1Pg43SPiqgZhc2D1PaznxpXgK8TRJNW+qB3goFhv1H18rjov3EWYZFXB4FJgV1GAGzxpzMKyTrciVLNH96L+RhSMv1uzyCPW1Js94BzD9MvYdBzIZ/JjLEhYwB00yS9LvvvhP+D631pRvBhpor3lWJY2pNW6bbnqdl5HkKhFYRAO1ijZd4vNjxNT8mxfzXfxHrYYPreaDKmOM16xePnT858VtUpNVsakp7DYwcqOwf1Nc5QAfb2TWgG5kFbSzzaUUNwjknbrbcdSwSJcZ8/Rp00PIeicTvYh6Ava5BjHcf/2Ars85ZK5M117dLyvQAQJZPHOs4szuhSNJZot/Hv8NrM5Z1G0VpykyRHw9RKCbr6FFBooBMj5LH2Kqb0Agy0Ece1dJYPsUks5thv1eUnQh/O+wWHa3YFa8qm4qB2VT2vLeiXsibkJBwGJknAD4QqZpD8krQsTbxOUYWSIv8SAoQ7TgD/OMnsSkKccdi9ihHy8TaNxBOdO9r/riUmXVivkhMg3s4YCQI8qdueDlsVyFEsf3urmGj7pzzDDM4A37fFyoGTfy5tsDXYvyJLrwe83gECu6pkkqEMIcV9rJawiemM3A2aV3ykVADXHuy0tvG6oRn4iwyYh0S8h7sp41ABlyEG6qQqRRMOOv/ZpqTgP6KEEHVADTWaP2LcMzaOwMPMLnC4vupnF2OJNeO3GTI/lLC0ViZaNFmOwG4u4kyG9pEVtwt9LUDHnxe0h6c8yyszG+FSU8VsddibNU7NxwMKjM=","layer_level":1},{"id":"72b97911-e2e4-4b09-bde2-f0f2d90d1023","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"认证与权限","description":"server-security","prompt":"创建datavines-server模块的认证与权限文档。详细描述基于Token的用户认证机制,包括登录流程、Token生成与验证。解释自定义注解@AuthIgnore和@CheckTokenExist的实现原理。说明AuthenticationInterceptor拦截器如何实现全局认证。阐述用户、工作空间、租户的权限控制模型。描述AccessToken的管理方式和有效期策略。提供安全最佳实践,包括密码加密、Token刷新和防止会话固定攻击。包含OAuth2等扩展认证方式的集成指南。","parent_id":"6f063aa0-15d9-4271-80a9-edc58df4f3ac","order":4,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java,datavines-server/src/main/java/io/datavines/server/api/inteceptor/AuthenticationInterceptor.java,datavines-server/src/main/java/io/datavines/server/api/controller/LoginController.java,datavines-server/src/main/java/io/datavines/server/repository/entity/User.java,datavines-server/src/main/java/io/datavines/server/repository/service/UserService.java","gmt_create":"2025-12-25T23:43:03+08:00","gmt_modified":"2025-12-26T01:24:08+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjO9Ybjo5U/vwUPZDqZYDE0jc33se7LE+29iR/07gzqChVV+iyWYOOAsx6vZQPnTQ9fGB6tAVpQUg3E//4cyqlphdEOWNwapL/NNgoASWM0jujRWCgVxaXAgheh5zDYbs60g6Z83yH9QdgH/pnBb6HgDwMk3s0rNQr+RRGrFFksBMbBZZFXKYfIMFcwAhHNMADcQ1NCFPQmk+EKjuccy5iH+0u8p7SAA8x0wkToPGlZpmLFofuxBB57YMaENnAzxryJv4Q4nOoiq2raIjda3MlUwVbtDrgvzVbuVKlKlkmfrE+nRAiL0cY22iDGkYy+5yGp/BZwIp3OxC9GrG2jPjC8U+yLtmDsZ6P4tMfcdkWe8gnyxqlGMk2rew9JPS5I8Q8KnysbmJnskVDMwGabUG2SL3bsN+8yAbiwIeNIbqsLXkiJluyJZZdAJhIbCm2FOCHTHVTushuc8SUczNYJ7QGrMaBSAaqwslRNQ/UnKQXE+EUW5NljKoEkOcleK+gJe3lCqIznuJqEJDZr6i7i1Bs5iIjKwHSAOnUErNnJCTlRmh7fCPL5Df92kqcN3HtuPuqlovwSQk0h8fvshdEjKByvq3gdGz3GvCejCe1Y1dLzUQNAqFqWlEciRc84DJLYNsJQCR850RS3NmHiIYfGEximkys1QqRT9J3+rHGqZdKte3J9n0kEJB4LSWEfclQdW8j6X/jxViZAEsNi1APZWAUUBS4srdPHH0z1Or1A0ZNzlhOIx7zCCfp6L+CLQeQTP5tBkjEEAbCdMysNlvLVLnk0m5YVrzOuTGHeCoDZtXNt9VSXCnrFLimh+L2CdZyY6hfcopkU7TUwMwvFu36ohCDTYcNtWi0I5C6zi6yQ0mgh4evyqjQfpQZTx36wFh/luh1zRpyGSWh7EpKUgAYAxaFXA+TV9aoUhfThY1zc/1k6f30U0BFtJKZsvbuXI8ZS8CwU1ACKOKr+cvVhrc9vLJ9SLzvrKJElAyuAFcc0OR3wRFRni+1OF/nky2cLw5IZ7GxFuzMjxo+059opwKPyG8YUI+QUP4/IjrnBMICUUkrSzJeVmUoy8oqG/IEiTxRG+75bz7MsjuCneB/wF4XjTOlZnJF77IzWIY304SpCOM6aJMbiLBgPsJA6z0saZfosWASt6NDL6aTzerw+83ViXzPQiBIhaqh1tNVaPrkQKkuQ9BzLpNB8wPALK9rgGZwsbWnz8Iqt9X/ujBNV0Kd8/Xf/315G1Xu6cTOMT8wsayB6JscISUtDrGCLwXvjzMRLdR83Cr+p0upGDm/TwSaz4dLyKFCiNtvVgpfq2uZPmc1VppAru1NKO5DoIY8/oQ6NLazU2Et52HtZdB0seLNeT9jPwAGpBefajEAbGOm4YeuMu6OniX6XAWBGSzue13yxsM0nNtDi/oO3N9rkIgR/Z/lsipNaSHPhgiEs1X0U/jC+FQFs3ToC3XGve5E8XgEGR8bixU1w3MI48NuFG9gYo1JDSZlt++e3mRSEXZVBTIMJvBv1BMkzsRUBgjT6eSVxiA9qtghQgXUxcQyBXNA47rvd4H3oQt7gJA3KxlqfW7JD3r","layer_level":2},{"id":"aa8efb1b-1c99-4fe2-a451-746364c7e416","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"执行引擎插件","description":"engine-plugins","prompt":"创建执行引擎插件的详细文档。全面介绍Flink、Spark、本地和Livy四种执行引擎插件的架构设计和实现原理。对比各引擎在性能、资源利用率和功能支持方面的差异。详细说明插件的加载机制和运行时集成方式。提供各引擎的配置参数说明和性能调优指南。包含新执行引擎插件的开发模板和测试验证流程。","parent_id":"bdbc7ff1-6561-4953-bfe0-96e43c8b3e3b","order":4,"progress_status":"completed","dependent_files":"datavines-engine/datavines-engine-plugins/datavines-engine-flink/pom.xml,datavines-engine/datavines-engine-plugins/datavines-engine-spark/pom.xml,datavines-engine/datavines-engine-plugins/datavines-engine-local/pom.xml,datavines-engine/datavines-engine-plugins/datavines-engine-livy/README.md","gmt_create":"2025-12-25T23:43:15+08:00","gmt_modified":"2025-12-26T01:25:38+08:00","raw_data":"WikiEncrypted:4J/+F+bhFfQhKH4ULf7nJ0almglmdegWjLAlfXv9aGeDa39QQqQobFNTjefe4U7/gA78wUuJ5P9Cm1vP44fvtBgsMpXJKiwfArpX8J6uDP/Kja3vb1/+NBFeANxlMBTVFr8LXmFa7kHo49Df298ySGi3466CxRIUyy4HslAi3NewMtdN9iynTKC7LlQC8Q9YY2nVx4j66J6peihuwY+j+SJfpl5MX6LZSbnnKLBcbQzcAQ6Du0yIFdY+Mob2PL+g9EnXYJuLk2MnRJjnZJSFIb8i3Y5LQx0OjJLx/NWWn3dKPgV5KCwUXsu1jDLRxic1aXfQLEWCNtEihyqxG9HgTo9HJDNOWjAuvLhLK4VPM9etgLNxD6UX0urHi0q0fBe/x/LGuXbo6ow/7hJsGb/HMe+94mwQIUc7rerSCefVgJXYO+zvbqXiHxIZ6ktJT15aVHJ5za46dq6o0cKc6NW2WVwoRJDJjTV1tymZwi1NRdpRaoNvUmmv425C90uabtG6vIqGiq0wil/y///BsEB4qSDgMdXqRF4AGCuQqOvNMVyVJeFfQKG25S4ZJntm9J+E2okkwPSd78CQ7MNnT+aGjgsdX7LEKgip194IZo39VYlTjQQmRmT5FuN+u99ygpY6nDrM85OAskWhNZPorzQ2RFPbhCtF5oP7cCy0NlgcO9zf51wzXC8H6Q9s8Q8p7+3IK2Dq34sY8ijsgSOh26bLjUj7yStF7kdI3SHtog9WV/RaK1jnhK21IaHCE63DXU8vObsbHklCaWfXusvrSYDrV5FxEeB93LKVM+rqskFNvNH8v2v1YSBbn3oli0udnNAnM8ZfJ1hO7WDvdcSnjddyna93H0ZPMY6g5MWACG2zaBn7ybLbYTjGxKsvGAHTAgR1GcLk2h+vQXCqPObWv3hDMKmya23jhbvoSxS0QuW3V/2NBg0ygVXPRXt8V8Ef83maezFX1bDXRFKZtsdanb2a6GpHRLoGpXlNd+z+P9Rf58uRD+7K4pH5wljPUaddDLUPizjS2UU9G0AcNLj4mo34BA10TFXeqmiXEku/l7CeufdIrBRn+Tv7tA5ePlSZBtoKQEjGaJQwWVg308poGnnrXh3cSKUZDAYeGpeOrQ663UoqjrhbSScu5P0OgvLR01O6LFIomnzXbEHVz5oCOxLjC7maYRb3tAeidxZLpf6peHJW5GCqR2u/7h5CH6O8f7kiBLcuH20MyoV0+MGIBD8orw==","layer_level":2},{"id":"6097d24c-f261-403b-8385-f5e46e22ec1a","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Oracle连接器","description":"oracle-connector","prompt":"创建Oracle连接器的详细文档。解释OracleConnector对Oracle数据库的特定实现。详细描述OracleDataSourceInfo如何处理Oracle特有的连接参数(如服务名/SID、TNS配置)。分析OracleDialect对Oracle SQL语法和PL/SQL块的支持。说明Oracle连接器的性能优化特性,如批量绑定变量、LOB类型处理等。提供Oracle连接参数配置的最佳实践和常见问题解决方案,包括Oracle客户端依赖配置。","parent_id":"e4bd9d6a-26b3-44a7-957d-46e0c9ba5cd7","order":4,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleConnector.java,datavines-connector/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDataSourceInfo.java,datavines-connector/datavines-connector-oracle/src/main/java/io/datavines/connector/plugin/OracleDialect.java","gmt_create":"2025-12-25T23:43:22+08:00","gmt_modified":"2025-12-26T01:24:47+08:00","raw_data":"WikiEncrypted:ZW4vMrVuodrLqpjtrVAFC67NvKG72gzYPgfZTu7L1U3+Jy5bfM1zqxuzktOLL6OvVasw4Tn3axn4nTgCrxJ3ae6+NvVRceaOIYbJbtfkp26go5x8AEbAWtCGRX7LaLWqf4jYnx6gm7Y7t/ZtSMzNPMcJtQruCE5RLXHYZdDg/qHxD3IaCq4qea7WMtZcq05qQ1gO+a1ElA5ue5SkQiZ5XSH49+fgDpkEbEN5F8m2u8VFsykoKJQRHX8qtEF1/5l/i3qhdLc6GoaZ6C5vtUBdtNUwcsHBfkqwCOv0s2ChXLNbPhpZHOeevIdZDiNMBV4k8oNl72Ah+ew3/JEn0ew1azg79qohb949XwIQMz493NLRcm7Zm0bO/0p1ZbUpE6zDr2jELZLPU9buCYbFysG9bj3AymRg9sGZpipkgHmdsseSdLo47aD/mfla0YchEu6RNup8tt4ZW1VB/o2jBrf0+u4sZMLNK3XljSqKDANy4cn87DyG0gMYEGzDstT2nmnOcYtndubyt0rKHdT6+qKBbk3V3gs11yClFMXOIUANv0MdbhU4KHesFqXp53dnJgNlSt7VkjE+BtoRClyZlMvpjiuw7ARPLijoN4I/r9dtx9TYQXYOGHIDM/1WHjiF1uA4KLkq8nsN0SSonxQro1nMGAB2c6K58Pfj5UfsXRd80q/ECR69FiEEuGOX9OZNeQ0GDbnIcN1iG+D+n9gQwcIPXbC14jxevf71CWFNJgyh0lFLHPESoGAzHPSIjq9aOVMogfHC7AQIITvYKYuKfbS3C0w6qVmBI4RlDk7awYFUMjflIO14AKJCTNYfbgwq0aEsYZBU6DTNuzUHbkmcyOrFJxZ58PGEtJXk5xa7NtUGUU5RdodDhgoSLKuoqXdhSKhEUdoFAHt+Y3yEJTXuZ0nZB6tEIqM/ADCPLa5Wrq3hcPmBpeHvXCZ5PTV9gKKcbJHF14l9yuMpgqyWagGkAbRCpMI0ZdKsxfmk2qmPXdeJIdy3/P4dTRWukCeCp5P21Zzd2BUwvY2pdIDVIQr0xFonu8/314LO4oI0s8ZrY1aWAQSWxg5f5lrw4nsQ3XoM/5htbo3331CGNUdrGuLdqpG2g6WIzDI5CLYxQKdW5vHUVZ+lL2dhfe865kXAS/YJ7q/FHoaEokaGUK0dbUDjw0B3gbZhl9k/8eGvqe/cILCYzyNU6RaIvYBTncxI78ZhW0JqSPiyAhm6zVuewUUr29qB4nwcSTJgTyZuurAsuC/+zI3Z3KAZjT3sZb5t2uMXEcBhxkuSb3IzpjDib9u8jF4Eh8QTqCQf3nH1JF6dJAh54DAR5AzhnikA18zgAenLgDBd","layer_level":2},{"id":"070c1d7f-c3fd-4161-950a-e255d4da1319","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"企业微信通知","description":"wecombot-notification","prompt":"创建企业微信通知插件的详细文档。解释WecomBotSlasHandlerPlugin如何处理SLA告警并调用企业微信机器人API。详细描述WecomBotSender的实现,包括消息类型(文本、Markdown、图文等)的构建和发送。分析NotificationConfig配置实体,涵盖机器人Webhook地址、消息类型选择等参数。提供不同类型消息的模板示例,特别是Markdown格式的告警信息展示,以及处理企业微信API返回结果和错误的实践建议。","parent_id":"9b0e5495-2217-4011-bc46-1d550de3afd9","order":4,"progress_status":"completed","dependent_files":"datavines-notification/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSlasHandlerPlugin.java,datavines-notification/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/WecomBotSender.java,datavines-notification/datavines-notification-plugin-wecombot/src/main/java/io/datavines/notification/plugin/wecombot/entity/NotificationConfig.java","gmt_create":"2025-12-25T23:43:41+08:00","gmt_modified":"2025-12-26T01:25:38+08:00","raw_data":"WikiEncrypted:8o4d9nDFpyCUM/Yuga8TC+ce/MwQXcrRlU8b6OSr3MnyI95YGa7fUAiuo9PklF1hPUo/dX7I1N+S4SH6hOBqY/YSpVK/pP+D6nrIKHxBSr/kWJLa81EyAh6tjupBdlin/ktq3y9PftJlk0BOGWNCPqIgiYgj6fhAMNlKtiQbBNd8lxUiBO2+fCqaBeEWIEj8d5J8TtszHHJevVXMUJIaXUoB51KkIJ8Jcd14fab20tZKoKsEyj508UGaSraBLN9XXBNdKqiEfau9VxG4tyzQS01aXFQc9z0Ya7XhyuxuM2wQuxHwUSdMKl7hnQ3Tcq5cyyncDpKktfNdmkX1vS3KvV00IsJerelcnJoUw9GEQhk0IKbfTTKyqGoO/Hf1FY2vfgO5ywXvHuNIrArAmrFGIspe9NRHPPJvgkkkcc9/jqTM/NapkGFIvShhcMquIeMIk26NnkgPw+DGFVxCbO39zq4cqCs3OvuhlW38Jhjp64d1+05WL8Yk99rffG8MaugXFOA9oMnO3qoc0vBXSKuhx5E02z95OkOkWd2iHflbL+TNG3CdlVbhcU7d4uQt+eS+fIIuWJrdfBDZxQy5XreOSGSmlG4x7k6Mw2cprDaj1yNZQdAGBCkScVPPFzu3ltSgpAICKmjzEju36h7s2g4i+s/gJEioERcTLsoC8cqKre/FAgMwP3PF6NbLEG8ZpDcKNWx4zvSw5wwdrWcXlAZ08jcZ2eTZnfUXXP5PnheJ736O8do6kUpVYrAwvju+tK6oRVr1lcV6Zg9GAbZvafoUIUfhEq3rsjMoSMvpKwYDI1Fv4ESZkTBdfSnjWwqQiIU5+CYqnwNglrzTwvzIOknsbHhr5EbmrsfGZ/k3XQySy/f/ZHGYOFk4xnC1/edUD5DHLk70QYtKkFQt2MvIuVNliOjbxcM32SlqfiE3wlMhyiFqqYZoEnKQPkxCM0eBXKVhOhVwS1CT8L+hjPcf9v2BpqcvojXqJ0bBNi96r2QredpzZXXg+moMFHVZcMnOCImQQ80Pkco/98Sc+tZkzVYsGbBIYmp0jx8ka59cuoRZ4TH8SYvOLyrje5SwE5GO7J6lB2/Jl/urGp5GHRcxEkVK1VrYPMrrW79jy+cflUxS/dokXkRIcBjUdiXaTJQVJlj6SVM5ZyDsyuHQYsxFi9DGRi6Zk9HB5qfO4uY4O5b4aU05sZCuixDERHR8yhcWuwQqy3yBnMxKPmDdGNXbQnxqR4n5mUJI+m7x6hRYkorTmuG6GmCF+GOpHq2xs3LTxjyyM65mCFWoh5QJNP0ngHaMRlcUZi1tOSsxPrx8oZnE5j6QJLFu/042XKRm6VwMVLZEBIdOYzslbH4oiInvpIEJ7riXToAq3gA0+Axy0GzZ4bPqQMANahQYKq0j/8uZjxFbs0rmxHbGisq7Qd/7m+4SVnwo/GM0aX/wwiiO9SC5JtS/4BoLjKlpyL/YrFCysU3WnYZHVKW10Lhq/R3N7LoBiC+OSDFkd2Y6JuEUQ3K0gLYALsm7pydKcjha20KMB8II1GmYo0YsjUWP0MOz8ojq8g==","layer_level":2},{"id":"ee36f1eb-9d0a-46b0-b7b4-ebcfba792d43","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"开发与部署指南","description":"ui-development-guide","prompt":"创建前端开发与部署的完整指南。包括开发环境搭建(Node.js版本、依赖安装)、本地开发服务器配置、代码规范(ESLint)和构建流程。详细说明生产环境构建配置、资源优化和部署方案(Docker、Nginx)。提供环境变量管理和多环境配置的最佳实践。包含常见构建错误的解决方案。","parent_id":"f6fd9d61-f5fe-4cee-a269-b29ba2583618","order":4,"progress_status":"completed","dependent_files":"datavines-ui/package.json,datavines-ui/webpack.config.js,datavines-ui/build/webpack.production.js,datavines-ui/public/index-prod.html,datavines-ui/README.md","gmt_create":"2025-12-25T23:43:54+08:00","gmt_modified":"2025-12-26T01:25:52+08:00","raw_data":"WikiEncrypted:+Tc/Xz+2j929YuZLugMAo5pY12hgkF4Uibmx0kl6WV2EK+tkUKUuHCwyp6IsHRLVo50j0eS2EUKPzbmoMfXIbbOKVepXj6yMakuV7VNb3XZn6NJl7oiNb6k4jCbRAtvHtYxve8y5SljoW4aYTWrKcWoS/3gvZxBmqGgr0grsS12U75C3mmVR3I9mwss6iXMJjJxTQJt8o3BZ5x4Fl4jUVPvlRVQxyCAN/qcQhFWko/rF6hcLaYc/gUZ1jHsNt6CDUmVUcDiZIdY80HKruAqzDq9RH6Sg/J04VGC6QX/K20hmcvS9S1vEIXZ8KHHHg4dCf3k3UXtI0bNr6QeXrs/VcnFa2jfLazsL0X2W+emIcbLYY/6yQoNkkrwugeiNYuCRHURtR0CGKrzJxsz6OlkZQUH0dOCfkEbp7ZtMYvaj5UinPGLJ6F+mgEq93VEm91/6wbYzUhrfD9kLG+rWHD16bWDritiw5wjUWRAD8rDwW8Nc1CUHzY/YCQYvw1pzosO4gtLEM0oovyxOen4sxYglmaNGH1mAZjOuLzxmcl6ICc0KkVOYmD8QheRCGon1yrYOO5ZSBeYGhyCFDW+NF9uxLybOMxf56GjpQraMs7c987W4c6nHwXbEY7Ie4vHYPSuMR6Yxgh1g20ntL6yF6zCvUWoqamNCkmtCGjyaSAM59iwkealRahsdT5g+W6hkUH20xieWKNwHx6IemuewRo0Dmm1g5UuZifs4dvOzho7KfGJj+JB+8NMHtFYLYd4H11kibhLEYN3VATDCvO7ZECIiFiCtSyjbNrcKJHhcIlVE3oiT0XTGLlszEYD3HnzUbAAXhmBu4yRywJnyfVTf2sx+NnGdHTyYdqr62n2PGi6Jo9+kMJ1/3aEZHkzGLzeV3oP3/658xsDxLzYYkejoKa56IlshM9UZ2qNFFkxdBNSpWchCakOgIfzufVBJdTuuyC5yzAJdmBbp2N076f13OOaXQF03uYENuyraLPS/BpM55Rs=","layer_level":2},{"id":"53232b0a-1eea-4a65-91b9-97803ab5210f","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"工作空间表 (workspace)","description":"workspace-table","prompt":"详细文档化workspace表的结构。提供完整的字段列表,包括id、name、description、admin_user_id、create_time、update_time等字段的数据类型和说明。解释每个字段的业务含义,如admin_user_id字段指定工作空间管理员,create_time和update_time记录生命周期。说明表的设计考虑,如实现多租户数据隔离,作为资源组织和权限控制的基本单元。文档化该表与user、job等表的关联关系,以及其在团队协作和资源管理中的核心作用。","parent_id":"3c7fa525-a12b-4451-8146-b1bcfafe2f1e","order":4,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/java/io/datavines/server/repository/entity/WorkSpace.java","gmt_create":"2025-12-25T23:43:58+08:00","gmt_modified":"2025-12-26T01:30:25+08:00","raw_data":"WikiEncrypted:Di1ozXFlWwX2EdovvmvRIpdrYY7uliykq8o0A0TbhGtpv6gadd3yf0EqJlvvHSt3wSUwjClZPnerw5yEc50LGmkHCcEw8MaOoZtaCU9mNwkdBWPUyIMlBNw9wLhJbiEpq+vYlq2oN6BIOauzRt42kbQNvo7hIVQr0U786g+/7hG0AOMkV61CiCw/DTMtRgkioL4meTPHyIGGsIkYVoJ5HOwFJ0AGnZAwUQsvnPORzr3tIH7hECAqj0jliuPWxkdna3MbbBLgdDMRm0hk4rxbXgVoaaauj3McixtQDidwxOK62nunmjvPE1Mj0YvSXa0I/MKhY7wjZpxXNe+wB69hEnROIH1DmH/Dt8GQ7D4dYX9vZgh7MMfZliIHAsdyki2Fgd2PMCTgKUzL7ke47a79ONmMg4V8GwkO4XD/KqDrQR+A3blDj8ArlGZpUbkcqMuK/CT4/yJDTZtwTB2fUEiJ2YCGhSrlezWgpWsh79vF64ptKJO3PvXx9rOVdu0t1hf8/OP12eiKIYRZ+f2Hs6USHQftzNSDzuC527XN4+kyF0cJK/bfvL1uA6MiHHPFyUl33dkTPRZGzRel+S3G9l2POGGnf+H3xqjpKY7hQ9Zi9LMm7xYFDDYM2sDWxg6k9RPfpf2oOfAG4vSDmAjKb8mgbJ4iq5y2cUl06lYXQVvA77g+SpSH1S2luHu28ll0xMZeLTiqX5fr8w0bFPfyZYe3Jooh4Docopr59egX1eLK7fxYp+ZlZBWRv4c6OBQdJQ6+y+P37Aex7ty8ziIPLtzXAZafxEU7ziVqX0llGn6KSKqjiLjxE5tSrx1JWWCgkFwml2+DBYQJJS0ZH0lVzS2HScnHL1pfPnvmeQTm1zpuogIhsF8k6HgXN4oZSHJGCiQGnRSEigHODPsuUfmhFizym63WhFETk54HszZ7ZxPI+5uEAT+V19Vuhi6WguBSjJtmAH2u1EbOJvbw0SpSMqboe5wMyHJ08+14YeeAn2niM7m+e6xz5TvZ7XA6UhLzRqwuwLZaNt1xmkmrwDBVcBjxtMSqZ1T5EcCCC5rwUo1hAdI3K3aZPXZJ7qlgZeF4zthzGMhXNINOTpJj8oifP6lsfTjvthB85iCqsFzcH260UC1nEv9RmtNQjVXI+XE77AxppuiQH3gEfJQ7Ftj5a8O+0A==","layer_level":2},{"id":"25eaa31d-ebf0-4074-88af-1517e7799494","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"SLA告警配置","description":"sla-notification-configuration","prompt":"创建SLA告警配置文档,详细说明如何在DataVines中配置SLA(服务等级协议)告警规则。包括SLA阈值设置、告警级别定义、多条件组合告警、告警抑制策略、告警升级机制。解释通知渠道的绑定与优先级设置,以及如何配置告警的重复通知间隔和静默期。提供SLA告警的测试方法和监控看板集成方案。说明NotificationManager如何协调不同通知渠道的SLA告警处理。","parent_id":"8938d0ac-a871-4818-9b4d-dcba6e588233","order":4,"progress_status":"completed","dependent_files":"datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaServiceImpl.java,datavines-server/src/main/java/io/datavines/server/api/controller/SlaController.java","gmt_create":"2025-12-25T23:44:31+08:00","gmt_modified":"2025-12-26T01:28:10+08:00","raw_data":"WikiEncrypted:DwnITgxBjfKXpaPTWaW4+oH6x4FNQdAEYUuYZOwq6JHvm8nFo/5obp48tFsxh+p9xB+NXOOVrjKt2QGzN9upW+B4cNDtcVq4kZrV7kIm5TKVC8p9ggvVwbqmlVQz0OVIleRnizvoBcpHBwTK3tG5bFaXcdval/j7ATFAra0crHoFVFDjPmSJ3ZH/26Do1TJXp5XghVu3KprcrpciV1QY4z8faCvsK50YDcAh0g/cOEaEFrNv7movl/746Y4hu+b5flczY6cXkGNYszJNFubfjH+rVgsyKZ4IDgPPshvXyIpmUDJTxiZdr0xp45zpi9RTrDCiLlTpjLnM30bC4+QNyzYTmFL2ubJnQCfkQLVXTw7WUOWfQOGMrWOLjVNFG13ev/D+s1/ydfrXApiOmi8HPMr7S3WB4H960rIczp3pGwMoC6f9YX2H7g+zh9s9g6+LatpwgkeorXAZklyJXaERrdNIwOtJqH99ywrETIUyfmWFE3KyRMX+Rtf/g0ZCjVnUEdXsC6B8E/FgBUQ2OT7y7Dk3pUCiMmIm0+U0hoP4tsp3GoibkHVaWQZtLbj3Rr32CaVLSNPcH4cnNPicZwOtowPIl9x+HmoglAHV2b3LqufLBvSD0NbYA/4nkyTFgYyLEIZw7FSJSkfKtvdGhBM19tTz6vVlx2cltqHWq85KWEAEuNbK6qYwi+682DXwMW+wCaMZpvlETtHI+fTQvllwg01bJ6biMAdlXD8fYfJ2w1BFwbrvmvAcZ5h2yB3IQEs9yYIUUY36M4zcEUSk9jJftK0O6aM+qHNvqQL26oKVMdmxLiiCyVVS8/syYuteIm564dCh3niCZh9W3YwmhctJCeSedvBa6ILajBEMGKxWvhnzQupSiiO+ouSIJZtPm6uq4U3Scjf1Bwrr1YUTO/SbB8y8ZO6APH8PU8vZDyGkqa+T6l+K/bNZRr532Vd10I6PH0UAU52O2f0xKPu7QlaEvZecCWI/LEEyWaBu5vVt3SvBYTi08Pk+oGlwUze8oTJ35JRwhXewgfIlEqmJRoBt2kw1LJREeXnxR7S/qr+T+qF/Ccyw1im5hmGSGQhF+mcQ7AGqH6UOmWwsXUb1Gwv8hME+Myt08dKNpjyWoB7JqHIv4kdeMSgDpCV9I+TjvApibeHKVqjDYKNj2IgooYq/6eT+Wt0Ln5X1M4e2CpEuSEE4r5LsP5+QcSbBs4mZQfBkjAyEPNCE+9glhgKa5gqw9k86nSAp9ezUgjhij0Zk3IxALHwLnX0xSdGyogA4eNLdr62HTknn4d2f1nwVPiubPpFYHYFQa7visWx6SsAVLdz6yXMF5Ys0kwOiVzP8mY15","layer_level":2},{"id":"f6af807f-13d9-400a-93b9-c47c59471da6","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"工作空间与租户API","description":"api-workspace","prompt":"创建工作空间与租户管理API的详细文档。描述WorkSpaceController和TenantController的接口,用于管理多租户环境下的工作空间和租户。说明如何通过API创建、更新工作空间,以及邀请/移除用户。解释租户配额、资源配置等管理操作。提供工作空间切换和权限分配的API调用示例。文档应包含跨工作空间资源访问的限制和最佳实践。","parent_id":"251acb67-6d5e-45eb-b64c-94b11aa2ce30","order":4,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java,datavines-server/src/main/java/io/datavines/server/api/controller/TenantController.java,datavines-server/src/main/java/io/datavines/server/api/dto/bo/workspace/WorkSpaceCreate.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/WorkSpaceVO.java","gmt_create":"2025-12-25T23:45:58+08:00","gmt_modified":"2025-12-26T02:28:19+08:00","raw_data":"WikiEncrypted:rOY1lJRvHID2h1aVFxzHUoSlUL7fRwwX8u25L8Pt6ZsRKEGya1PqjFIByDtuK5YaM2JFg3xyhNTceRboUEcbAeR6Vw2T1y4pfNtY0pvCh5HoajS2lr3I0DmfZpCgo0YsZhcLUQCC142k1FCSEcF0YFtLXpxgUplN/5WbALnyH8fXPIvDBYC1uYlGiYa0SwQN4CpRmFLpaIlwbtyaxm4xPTmlKXX9/4jd7/lwVGXS9G+vk6f6vHrs4RgF7S6Tu4xg3N1ZCslZ7gkqzjXy8/KvSbTorMioduETWEY6bhdeHMsZTwqvIpo/i285Y5AmYB2xp8IAVF3GQw7ZsuXAkUTU4bQpPZzuavYTeKr/FboLWaFj30dxCwKxy52XvpmbXEtP9KAAj7HRPN5IhIoWZ5n6kwWp+iBMEInAkCv5M16hizYPieXFFZqxm9HBVIIDHfhCKKeStUglksV7GLiFkiiCv+9aAkyD3ebFjDDyDuhNHyKEQtwoP6+VGl2skUlamsjQ9TfxCMBxRQsQ10Hc4X0gVExJ/7Wxwx5x9VaNTrQfTHUz2w5oOH/7Qmjx8vnWeeInGS0DlB3x7kPllTrfrGy3iexMIPFtDzCKBEWA7wAN6OIeKV3f6mOYTMDbFomZc45jMhE4lFQ3asn7Yn6fytMDFylQKt/b5lwy6TOUxcBVtJFzXIp2f+ubrANfTDbNtLyHXSkUFv9iHY/2VoPkCfOIQK4OemBDZMMfU3bJkJvkyzw8I4cSiPxcRc2bbXxu7iPFs5r9AF9NrBRwfKgavTrn/8ipRorFaDz82SryoXPY8XLMddIMLK2UYnFYLdE81KtS7W7qTIKs3BaMmL+896CMRWX2ETeiMf22TZoChR8wOO8LUEt70kuKvhiRBRe3g/LItj0gt6jb4U7kLwS0e6qbAR7VDXdAS6bIxMjpT+hnvFP9mGpuWoF3Bu/tcGeMv+kIcvGeBT75cNg6w23K1Q7lwirT+UGlvQvijvZ3NRsoLgxrotPM/szSQFWb6XYx7NTxQgVK3RB8Kp8I40oNXH7g1zf1+EZn3rlZyIcJ56qXJTsr4ibnzQagY54x8h8PaZYiRAtGdKvnPAtdT1byRfw5udkUBoUBDt1tKpUAAhklRFV0pw4ct1zEFZHTRGeVw2NJZzkAAUw6w+DA2xuKmGvnuupgisiqtZlcNB6WcNKaVKbOdYdifex0n5yqIXf+06oFcWYLnvB22tNFsJ45zePAN6+eXcVPivxzNu8vH7vNTZEhHHY1mi9ioFt95xRY3WaW7zKdGfDANMXUwsWjf5xQ3J9F+SYYUs+nCyr2eDOzPeq5y2VW10TIT0S91qHLJQy0","layer_level":3},{"id":"9c3d0cc6-4854-41f9-ae0c-718080bd9671","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"告警服务实现","description":"notification-service","prompt":"创建SlaService和SlaNotificationService服务的详细文档。深入解析SLA(服务等级协议)规则的配置、验证和触发机制。解释告警条件判断、通知策略执行和告警历史记录的完整流程。阐述服务层如何调用NotificationManager实现多通道(如钉钉、邮件)告警发送。描述SLA规则与作业、数据质量指标的关联关系,以及动态阈值计算的实现逻辑。说明告警去重、抑制和升级策略的处理方式。提供高可靠性告警系统的最佳实践,包括失败重试、消息队列集成和性能监控。","parent_id":"ae9c4797-fad2-4104-bb0e-09c584c89e78","order":4,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/repository/service/SlaService.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaServiceImpl.java,datavines-server/src/main/java/io/datavines/server/repository/service/SlaNotificationService.java,datavines-server/src/main/java/io/datavines/server/repository/service/impl/SlaNotificationServiceImpl.java,datavines-notification-core/src/main/java/io/datavines/notification/core/NotificationManager.java","gmt_create":"2025-12-25T23:46:02+08:00","gmt_modified":"2025-12-26T02:28:44+08:00","raw_data":"WikiEncrypted:4+tXcquKioWk6hL5AaAVvQnOsxTjpbEDZmZugV9VtUEh8QyMjX8lfRviEYoJUeN6+f4PohMn0fPhVQHaY2X8169YA8uBwnri+UaMzDxxrF5P/ruQ+2s0+UhLhJ6VqOfKi0C4oFUr/Pb83LLOaEM4UnhAZ+Wc51ySXhESWkq4e7H+vI9RxW4j+r/n2RiQYbxUgz554RIopHhp7/oVK2eshROz1Z6fPJ5c8WBlf6daVrvf6iVpiW5RZnVPZJW1FhCHggExhZij7DTQJB5ZU9j7Lb07eTAzDjXVln+IYluWhCNbWOlWWe8/JTuRheENsQy2IoKOuYirSQFU4G9qHlqHlKkKzgUeb31lJKI9+f8zVY4HppmVZ6/UERQ49RTFKbsp1Ec2oG8n7AXGv7FUQacbt5Z3QtNi6DNsXOGaf9zEIgjv0Z6uuTN4Bb9QzlRl5NxqMK92z9/jt3beo2YQVZdOQlHsM9e2UB98T7nRVpLdEGMpbRwycFHfWU/fpTcDKqIMyS5i5PCyIllKUX9LRkN0R+OseDIuE/7slbEOAtGtlGPeM/r0kpUSe7lLkVJpY2aAqUaZ8V4GM1IkZB5XrNh6RxK9EsQuy7fZwLJnspzaKYiw+i5YeAYnuSzEixlAX71C3OQ0exFs8EeRNMTHGzxfY9SjMs7ed6cmJZtqreSU/kwG8LUqNswtAz4AYS7eXpmPPrUpcc4XGxx3wbtjfEQbGwZKyR//KvMwu3GstVw6784mw1yVOh4lUr3hoIPXVrV66nFIcAR8wdJPLQ9UOMvR3CyT6jfSiIrNkQxUd372LDavBYa/CTJ5jij1N7bkwcDrBOrTev10rJltkoAdEMHNFzpshouMrach+mY762YgQnHMCWYniMV0p4A0FY059ubhuC81DpuWSyYPBwRCzhF+/ay+wWV4HyII2kSaOsFY6xnvCrMEs+pD38T3yQlJesF8Ad24HvH3BdcERcx14WeMYFDcNbhCAtlSjgu50XOtQckQUX8EDBVnwL7eprcvk2ZRUXZwIxVyaXCSEVqqTzs9lv7FdTVuMlGKvRpdVwTJXGrRKWi42ECgK1V627JFHj+WYkdwO25GIXI0wZoItdlGQXWiYsmS396oSZk4+0+fY0liVKPshB8lRrfMoXgw3QqQArPOwSn7RxS/1Lszxsvsv4+JNKG1/n0aX+9wAsm4+es7cQnIhrEgODuKQqnsE/NAFOAnHgpuV/A6mMFG66lxIyenTo+E1hcwENnIX6AVxoyTo6h2rFbX56K1E0ekDlKfP1/YRtrWxjHnkXcq7LJ+9hJ2bvVk9Rl/H557IZ/m+gkulRra2B4iz2NGaWOHqnvOdEz4VYD4arpg8Xr9SofZlb02Vrp+inyqs0jvHyEYvZU3zghzk+jIC9O9GBj8x3tXkc4Exb5B2PMqVWS43NR6g3VzSwuVtMl+7ta5n0U5UQuECinQ0oSkoZMalszaF4DlI4p56+wD8Aqdkz/nSLoJIBlz2S68L5gZ4fm0SwU/5oFkTPW9mPl/E/DhKEUu/wmxrnbaAmTXy25hrrAXafBhuXnIiiELtIdjouBEhyoVqc3KneD0C/oxTwUu8nvKaHbKvj5CJl+jWi5GCCuGc7wuBhIfFMVStJT3L0zD2yp4v4vVO58lEQtSgjYuUHjG27I1gvXIhsQjlJCMQ1Ee8vV2ZgWHwO07C6+JQoMltYO0rcJWOo1neiiABRAOPeTa25G5IKQVZ4zGFI/oQizps8zrQfmUSnoOpDAVSCkiL5AK76c=","layer_level":3},{"id":"72541630-5f9d-45e9-8334-328fded1f2b4","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Presto配置","description":"presto-configuration","prompt":"创建Presto连接器配置文档,详细说明Presto连接参数配置,包括Coordinator地址、端口、目录名称、模式名称等核心参数。描述Presto认证配置方法,支持基本认证、Kerberos、JWT令牌等多种方式。说明SSL/TLS加密连接配置和证书管理。提供Presto连接的高级配置选项,如会话属性、查询超时、资源组配置等。包含Presto性能调优建议和连接测试方法。","parent_id":"860d9985-eb7d-432e-a1d2-69e59ae12cef","order":4,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoConnector.java,datavines-connector/datavines-connector-presto/src/main/java/io/datavines/connector/plugin/PrestoDataSourceInfo.java","gmt_create":"2025-12-25T23:46:48+08:00","gmt_modified":"2025-12-26T02:29:25+08:00","raw_data":"WikiEncrypted:Fcz3NIS0jAqef0IQQaji1XTZKTJzVEQYWH0+zM/ouAG4MraE3bpllmaotsXCOD+8ga1jvlJG3cgMQ5ElfQ64dTrwZPGR9rIsMIrR6GqOlpMrQtngb24uVTkfmPAIsnmU3JsdVeNSm2BOwXSsQf+QQJhqkaC3v+RHl7Nc3wI+RzZJ6lqK6MtRzpesNNsFeDvfWTs71r0AADA4ffyEJP10Y6RHT99TYEfpu9OHFyn091H6ddWkyhKZ0IIlzXUsqaRNTP0zNSvWD+99cU218mMMFeJPkqxk48eP37sfOHKm2WCsZ84dsdTE0cCtgnm7nRBdvbV4qowBTWpI96PcSokk9PWz0qA93fbvUIF9mOqMuU0dWuG4JL1ZK6ZZawJFAsyBj+B3bN/15E9wisUWFps1freKB73JFmmDYd68nl+ed4tmSlVA5GUwEFAUrj6/GLCNAgLVhoX7EhB4eRntaDiXjCSnxWi/WslrPzAKY28/mtf6jCU8KUDp0R2+KixBNn3rZHBq62lq5P7N8YYfXjH3yW53XZwMbcsfWWHptLB4zi898GNRp/6lQmHVFArCLUc0t2QdYaeeiHDCAk3PdZSceUn3hDqWcGL3XodXzmrTz9gBo3ZvVCLke2z+pqWi84lwBorwnxZ47/yvXZV+NGMBtayiyqQnQJyTONe+dOjlptDixV4Sq/M0wWv6IxWDagAruiehpMEfSudMF/y2zmNESwmR1CmOQF3yiJGPhBM5nHee0Qhb1HmbgMrV0fK/tZUYFMeRQOpG3sMCKnTPHMLLm+HEBCTUYodJWn1eB77EuhVqlpzi9MXbj0poKk5BiP99nvx4/McxPXBkThe+EztjB3mW+EZTWyrDH10wDp7bp2UUMICvd0EVDdXYwFBZk3KQNaW8/UMps5fUnnhH3Peo63EcFoitmrY0T3OyPDEyd1in+rmOdt4q2gbOjxOeBHnWvfWPzzDp3hY3mAcjpzN5FAahmMbLO1t8Hc50mlZ0o2wVn9zsTex8nSeu1ERQMxHvvmzwl2Bc5hkCTfuKPInq0eFtxBJibjnMeeJWDFJj+BdvoYAIX8IWZ8UyaopQjLKZfSjbZhudIhvAYq0Xc4HqyrZbR7PTWKSDXLtz2wFuUJIbSXz0/yeZW++64sHuUseY+ZJifPjzgPKbC03sWpUZGvm5ScXX+f7J76EtOUJAY3nbZIG9Q3ltKcI4RVPz9Fo5","layer_level":3},{"id":"f7482163-91b0-43ed-b702-cebf50029b91","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"插件开发","description":"plugin-development","prompt":"开发插件开发指南,详细介绍如何为DataVines开发各种类型的插件。涵盖数据源插件、检查规则插件、执行引擎插件、告警通道插件和注册中心插件的开发方法。解释SPI机制的工作原理和插件开发的最佳实践。提供详细的代码示例,展示如何实现插件接口、配置服务发现和打包部署。包含插件调试和测试的指导。讨论插件版本管理和兼容性考虑。为开发者提供完整的插件开发生命周期指导。","order":5,"progress_status":"completed","dependent_files":"datavines-spi/src/main/java/io/datavines/spi/SPI.java,datavines-connector/datavines-connector-api/src/main/java/io/datavines/connector/api/Connector.java,datavines-metric/datavines-metric-api/src/main/java/io/datavines/metric/api/SqlMetric.java,datavines-notification/datavines-notification-api/src/main/java/io/datavines/notification/api/spi/SlasHandlerPlugin.java,datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-25T23:52:41+08:00","raw_data":"WikiEncrypted:ukPV2tcWPRGn89Upsee0BMJPbHQX0hwXHlyElH+Po4OMND5qukbyLNiyKhqcozSK7l/XPUqpOuMmVJZuaFxCDQAOXO+pfuo5Zx7qR1pkM82QwIgXa9bLXqpXD3oghyyFAOoolu9/TbJjw6AV27Pf3eeo1Kf1gY49EizFGBqVJ170EOgE90KK0E5/HRSFFqxQPbdNHvw/Vpc7mwsfm3iD2B4Hbr/hDw9wvb+D/fSTUT71q7gsxMnEVoLn+gqXbVbk40+PPcAhZrcLtE4n+Hpwp2wBGG4HbXOZ4xoc14B0UfKLrJWl4cq9XYovqbGZqQArHGKxd5gfC9bUYarDgZmM51GDgG2L3Iez4MyWD2h9coSdLlLjktLo4a+IBGhyJfEGW60DzIBtuuiKPL2bV8MawDx5PZ4OeFxE8zebaFM88/ThVX9cznk7fBHATTgpl25RIbu4mrOfjSu/Q1N2YZXTrwmlDEvIRSzPyPGtl0gJImmz+ijwN9CyqVa7mK580ZOrXOJlwOClZq3b47H14L3Gf0Mjbgx9xlaAsTMWmTAVRFLB+7CVwFQ7MGVHKCzTeEqnj6ysgrq9IS3nUDhrXAGCverQczb+2bdvVhgCVv4yDjgzm8Bi+G5q178mtvfMZTI4Qise8+8MAC1EKUfdV1hTNK+PGzb3FqB6VSnNuu8jTfPS7sgAma+SDUrI07WFHXapY/SV8bn5VbsqToTupJFEyT3vSI0flMxZMqamOLT2BFO/YjwNC/0NInQMT2MF6aHgJCE7bqWBQEj6x/TQpEqgbIyqLgDcnBxm2cHQ/i0G6qQqpHVG1pzKajq1iWr+hq/vYW2eVkgQ7J7qn2yAqOsM/6SyrExGyrmM9xy2JvhlOBmcHe8Mxkpdmc0HauqTUNzNrZ4epLS+tJ0IGlG4WhBPUiP7H+62zM/DXoNby8QCUCYclBFiNcl0lNwwZM5FNZHvQau3WohIIALWWtz3DcIoSanMrc/dSAf1q93sOK5rXGSWuuO7lsBe4qnmOdT+QfdYBcrutZRc+GLRwQbRTBtGvK5BIzO8P4EDKsG3tlHdnU7BO8g51vRw4p9yyNPf8uSPoZC/s5A97FR4Cx4pXCsp36j1e1uBcP5eY9zH6M2BUUUO7Ex5GCHug6+RW0ffFZ60uWhS8eMNmkz7RN658hFka+CpD4VszNlp5OV4TkCeiaeWAULtsRUFZuavYe/Ynr6jJqV+01pGieNG0ew7GG+NZt+Q87NLSjT4zFtS6AH14CexbnzWsm0rKRh/JRPD9mBrCAk9NDdySXZ1QuYP4dLFx9wq4SzzuMfZMFh6mdsDJvSgQEaiAQLQLbOb5hC1Pmkd80G8ZsWpwwoBF6dFpr26EO/JmoqTfGkbpl0+xvWnggsHeGU9JOIHPxE3WIj7Wt8WXsS3N0ZzWL0AmrDzzGugttYSaXKIH5jLH5MSbXZPy1rbCs4Y4S8KNH5I7zjZj+ccqWu4t5n7ULGt3m28UoaY7lKD1pZ4EUxFwymJYfV2iS6NYddns1OpIMCTebWDjz0egqF5lyI8h5pDXXQjZVEBf5uERRSSSKhU9izc6hMU6AguWS5fXMgOK+pPalfkK88dacK/Qszn66U4uOotUouNnCKgjYYPNxezhgf2TOdi3wS97CwMPhO8IFJCKVxFFV9dJZZBYYlkxXDmf3ARKuoQzD3/ZlgOr8lhczpGHxOfCgs="},{"id":"3d9880ab-c577-445c-bb52-b4ee5d0415a0","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"datavines-registry模块","description":"registry-module","prompt":"开发datavines-registry模块的详细文档。阐述该模块作为注册中心的作用,包括ZooKeeper和MySQL两种实现方式。详细解释服务发现、分布式锁、集群管理和高可用机制。分析注册中心在集群部署中的角色和故障转移策略。提供不同注册中心的配置参数和性能对比。包含扩展新注册中心实现的开发指南和最佳实践。","parent_id":"c391a73d-20a9-4e3e-b13d-54fba38ef59d","order":5,"progress_status":"completed","dependent_files":"datavines-registry/datavines-registry-api/src/main/java/io/datavines/registry/api/Registry.java,datavines-registry/datavines-registry-plugins/datavines-registry-zookeeper/src/main/java/io/datavines/registry/plugin/ZooKeeperRegistry.java,datavines-registry/datavines-registry-plugins/datavines-registry-mysql/src/main/java/io/datavines/registry/plugin/MysqlRegistry.java,datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java","gmt_create":"2025-12-25T23:41:22+08:00","gmt_modified":"2025-12-26T00:31:58+08:00","raw_data":"WikiEncrypted:hvwFz+sIainc/WWi9rXmKZpRRp4YfaB+yawRn1HmpTsWlyXBVlbJhNnk1XHAinBEbCWRnkleL4gISP1+MAKpK5R7BC9GrZHgKGbe1I307u4DbgQ6qgtKsqGHwPnCyhAs18oMLEpZ8rWzQYdZdJQGlczmlASNA3OwDHhqo6tESe7f+K1QotGTOD3iqjBzXwQqy0aVncXt0fNc6gqpzp4Zdg7+IFb1yFLzPWm10Iv/epk7ik2SKmmc/xCJ4MSDcFUpNQTwFDwrELvVjPYozZPVp8WC3wXt34dYiNydrVDwT0z0p3SBzcjmJTEGLVoG3b5ICctveuEfGTMCiNK5je8rRJP2P9yjBQ16n59L1BsYekHjDIp0dphldEDja6Vfd6YN3PQ7L9SPgKVsaqPAYbfyeYA4LPqzg/g8jdsKvra+tBs3niUnw3lbq6ptP/nIPw8pc8FWz+5/A0JEqp/+3ZG3KZbZ3hHX1J/FCGcKubfSIFqgc3BHrjyCGuT9MZQ9fN5YoUQulExO2xCDLvIXLl2cwA3ei6ES5n4MYkGF1M8mf8nHsvYprvTTv7MDeAPOMBMVdouolLWqxGXZyEwVp6Tw/KwNL2skG2xjIwJum5mzTdOmKD5tH8fVfRSXTv9R+XUY8m5X3Qv64ypSlG/JLTHT6wp05RrwV+HtH2OjvYCptJb8g7pIstKow/vXE5HXvXpHj+60Zx1rRJKISsy6OHQaIZ/LHydUFv9F/hJmI8Ms5pUnv8VYcBMEQePnGHuCReJ/ewjuurpS0LoYLh8d2nX0S4/EH78eYc/0l7Z6c93oKPvubihKBXqnms/Ydt+F0hhnCgV5hyrva1JCO1TwhE6lkKZsHNLFmY7MPLVsto4dG6WRVpDCAX9RuqToNzo+qxWR1Hm+cRkM4aIL5r8vFtg5rS0wU/2ZuQYa+Qy9FMI+sNGOsVohsIfPVxc88ItVsItCN0fkmv+LTrIGEwghXWc3valLgKtQJF30Hl4l7pJz3n5QVT7+3tx1z7bjnPfmwxcwSgCeZ9/ETkwxy+OPEUokeBcbb5/zwRBc/wVqHtjRzs9llHJzBxWbUHUBi3xUjixJb6W+NrOfvyzEI37km8+kW9s4argZU7K5luOwGJjsGyJO25mS6COagg2LQQblT7ijGjJTgUvvdNnw4bS2/HPZ18DwAPOinBWMTdERErieRm0vAdkV/sQ+Z9tbiZE+UHf4i7N9t33rWe7vnOnBGq2ZG7/tZiV6aqjyWOfYD/uAVtB3WlhNV0ta7wkjuBwg/ijSBGkG1iA4wwvWc48WB6AwkPmqukWIGRiKP0Iztdgnlnn++jgzYOCzO4hdBfBqK/ZXQbyREcPgxiuJOwWI50vRW9zhCP9CjaKLVPfYb+OAaJhXazkfKw/maE2iDKLImqPuTZ/5skM+u176G//PKeISfOcM+hfP75c478cMA+jr6D8=","layer_level":1},{"id":"67c4da86-576b-4264-b187-42216255a143","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"安全配置","description":"security-configuration","prompt":"创建安全配置文档,详细说明DataVines的安全机制和配置选项。包括用户认证(JWT、Token)、权限控制、敏感数据加密、API访问控制等。解释如何配置验证码、密码策略、会话超时等安全参数。提供敏感信息(如数据库密码、API密钥)的安全存储和管理建议。说明如何配置HTTPS、防止CSRF攻击、SQL注入防护等安全措施,以及如何进行安全审计和日志记录。","parent_id":"5d2798df-80b4-4ceb-b66b-9167054fa556","order":5,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/config/KaptchaConfig.java,datavines-server/src/main/java/io/datavines/server/api/annotation/AuthIgnore.java,datavines-common/src/main/java/io/datavines/common/utils/CryptionUtils.java,datavines-core/src/main/java/io/datavines/core/utils/TokenManager.java","gmt_create":"2025-12-25T23:42:01+08:00","gmt_modified":"2025-12-26T00:32:53+08:00","raw_data":"WikiEncrypted:JNhY5K+GVMrcGagKRy9Mk7qQ81FDOCGCw8cHtrGiL2HFp1W0YavTGKuiloEP1flrcpgCe7c85JCVnRP1ZYxMzh1IGL73AnUEjq8EMvQ2p9RYksctJbmsktkFTNzrUTBBgARogZH27tGr8iBDVNEGYrdC3lmzXzjXEnMQWA4QE1JqX3qw9gAuTSFCALyE0TmTtfoLiZ20gHfMRg/3SNpmkheviLrZIL9MTOflN8YCRxOmy45wBVsT5+RP9FSN9+jVfc9sgDYMmPSSQA9sZuuj8M/gLnmxFdW1awCjFvzwzfmbKNdRsP8CryUNZ4zhkbGF4E87CePHlwlACwOnKs/eiDDVaFuBvfiebuLv4q/pzcQE4urZZfst426skjnTsMsoDQPNUwcTKl84916bLm7PfAsX2c605gHdDMM8qIPVVKtX4W5FkRX1Fe9q1IPl71qTINqwCyjEmmxhNHRAJJyWj8W25KeHOMgc+ASDL4/WJJB1NPW8a58ge8c+9G8CDDAGAFwVe2ZRCpJAiqctqU1R/LpY6z7d/Mpa+dVMCBzvH94s9fANJovt7R6kB7OGxz4LdPGfBJZxpD7N09caxhroyMXg6QQUazWuybZf6zNBPiIJzZRdZQHSVq3F8pH6YxhtF0+D0SUpFEz25vry1xP5frgipwzXh+VSIhhBHvlABqd7GDXk/oo67CX2YsQki9R/yUWH9AfRGcy+Bx2yY2XM7gEm4TTSspoSuh5InRppjvnDFm/14EJtS+Z738kdE15AUEMn9/zMUVn1YG7+TU/BL6KiJlPT6UxWWVLC9SDNXyNoOhipDLqGEEPgjKovV16qagQSwW2f0dQ8gFAf+Dh3vgtXejU27XWFCGHf9OgDY20H6/meaIty8OtuzEIEVYS6kbWnV2J1V072bDyPMEMgdNhgCdSdeMRm6gBimvCVfR9cj+0MCffUwwfB/e11BZOXpkzYFJy9SBnESdIt8GRryfbZijUFKx5yCYpaf3dq7g1vRL4vcnrqPiOex2+2vyepJXaLR7H1ngqLUEaDVonxfH9zM2oPjNPj/mPIsNL50w6g7hTnZwJFTIFE7vxHHCLV8tDAAL7GtbJ+cu7SZ5pyJu2CzrmvWqSAlWUGgGgpBA5Dq5TrZ6hYcKe1vqRl86mbmuBP5eYpv0OXcFuX/PJjz7nukSBnZe+OKHVq2szZclduN0EqoJxOgpEv3FYBKQWzemCqSpTLEbM8FaaNd0Ib0+M6R5aGodZpuI1JAYAmoNiJHA8LhJjJTs2TMqk8J0MQezd8bYt8qN8BU2wuRHMrJ3mQpl8OOgeFteZn6V7CPIQHUzTClaREYW8vT/2NzSGK8+rJ4buqY39vygO6sxkrbNaA9IN7r0lNq7fBDLMKicg=","layer_level":1},{"id":"d5f7d43c-5749-47b2-b0d2-19af59147dd9","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务调度系统","description":"server-scheduler","prompt":"创建datavines-server模块的任务调度系统文档。详细描述CommonTaskScheduler的核心设计,包括任务队列管理、任务执行上下文和故障转移机制。解释元数据采集任务(CatalogMetaDataFetchTaskRunner)和数据质量报告任务的调度流程。说明与Quartz调度框架的集成方式,以及如何管理调度任务的生命周期。阐述任务状态管理、执行结果收集和错误处理策略。提供高可用部署和分布式调度的配置方案。包含调度延迟监控和性能优化建议。","parent_id":"6f063aa0-15d9-4271-80a9-edc58df4f3ac","order":5,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/scheduler/CommonTaskScheduler.java,datavines-server/src/main/java/io/datavines/server/scheduler/metadata/CatalogMetaDataFetchTaskRunner.java,datavines-server/src/main/java/io/datavines/server/dqc/coordinator/quartz/ScheduleJobInfo.java,datavines-server/src/main/java/io/datavines/server/repository/entity/CommonTask.java","gmt_create":"2025-12-25T23:43:03+08:00","gmt_modified":"2025-12-26T01:28:01+08:00","raw_data":"WikiEncrypted:DfAL4INOq29Pd0V8no8kjJZDp2axvynSrNCwWayN/A56LSPAWwHJYremR0FFh5QK9+wE6RU2PT6H01f8DwPbhZrwngzkRd55kg7X7s8SNYEBJoHEngpr5iZRBoJjCYWyARgZukvgAZrqMYTwRYPXrUDukDhSIJm8/jlKUXQLD+ICd78HCJvBWDy7r8gfoRvQBE92KkBGL8b/HsftQf3Hnfp2Z/hqStP8YdFygM2XJ7EvDzDLkamy/JRRw6Zrc9zeW9SdRT7xqIFLI2KsFei58KYlDE+rD1Wdb2WAnMhPD6NocpQ5lIC/sGw4NnQeKR4UbN5Hd9ZbswEEQ4w7gRD81LCs5bPYq/3e+LPvj/uEAYRgJEhxsVLrBD5Fh69LggI1wCvYBqZ64mpW32lA/GL5IRFVgiPBuXilOSgmNuqq4F7qtECRRZi3LhSG2ls4Vg/l/8ek6tyuBbAdmeKitFfNwZLz18huuBi5MkVTOjTNR/UYElH2xwytDBjZ8WYXui4XviJEYVRlwncbWjWg5hAkBhZezSbANJLpUGo7sxR4Gm9kL1s1zpU6jaj7G5TAOPJA3BalYz2NGEsaSApwOEvsKwJJheHBVmr+NCAZWACLeiJHMldg2BuANipGvkIF6are0b3ep2OaPFwAElnFWDYXt0KwigDeSKWAu/xo4PypYgLSmRBGTpVYHkTDWKCp4VZGz3Qc8sDu4lyF30KPWN+wCajCKAx9QmPKuVlAiSFujE4RMNrYT9XYCOzEBwXStwK+ffFQA7FySEsKm7Cq6gjrhrDvZu798vSkn3mA4oZVcaHL7wz4oGGok8/HzLDxI1b6zMDy8PV0+eFUxl3pHo2GPZ9inC7hvVp/kWLawT65cwFJxY5ePQVY5M/34mQz9B3x1ausnjnFP20H0EBzBeeF+npCV9obMam90siKXaWSPagbtIvRw6Y1LVpcc7Blgc4DqSmy0NMyi/NBgVSuqTlRjglrA+FabcrNPKvKzkRS76w16QXgNe88x8Zi2P8kdEKDXM9iD4hZeGpTTM4DBUj5mdvINQRZelj5dUo6v7LMYF8Pol3w3CwKO5bQk9gg+MkiDaf469TnAjwa5YXpASUnvB6plhQRJrz6kdJ0dCPKQ7hZ9OxZpoX2/HnfctHD/Psk6Swoi3oXblrtB3OUlGTnajGQwnNHYSBA+V+05EQizkkdLuccmETeVCs2oTPuFCdZ1ttdfcSlP+Vj/VPu9aeMxDmYgTuo/J2C3udZDSxYbns2tyZflREQgzPP0X9LCOWKlc5FBtGIM/70UlsTdVUWLB8eH9LCuOvMjLEeViXYB5f1LIY4KPh0wETTPYOKDvgux+z2tO3sDmtEzDhlJmjRpf2UzCLjSlLg47br0Xaw719HMabhBE7R+ISErMzEWD9JECzbtiUlx/YEn/NNIl4v3Paey5DD5vh2x/PNs/6PdeAoXxh3zOYexxw6AbrTk3fZB4Jc5X/f2oRa1NjpIGaSbyK/3IzPGxV+0rME2wbb5DQ=","layer_level":2},{"id":"53211d84-e495-43aa-be3c-b264852c4be1","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Hive连接器","description":"hive-connector","prompt":"创建Hive连接器的详细文档。解释HiveConnector对Hive数据库的特定实现。详细描述HiveDataSourceInfo如何处理Hive特有的连接参数(如HiveServer2 URL、认证方式)。分析HiveDialect对HiveQL语法和分区表的支持。说明Kerberos认证的配置方法和安全考虑。提供Hive连接器的性能优化建议,包括查询并行度、内存配置等。涵盖Hive连接的常见问题和解决方案。","parent_id":"e4bd9d6a-26b3-44a7-957d-46e0c9ba5cd7","order":5,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveConnector.java,datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveDataSourceInfo.java,datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/HiveDialect.java,datavines-connector/datavines-connector-hive/src/main/java/io/datavines/connector/plugin/KerberosUtils.java","gmt_create":"2025-12-25T23:43:22+08:00","gmt_modified":"2025-12-26T01:30:26+08:00","raw_data":"WikiEncrypted:cICBKpGgTpGK8tUTADCA66TLqiRvDdeibD5SY0R8cHxHBfumURNi8PNl7IWAyz6kz/qZ/UhCspmkUXwTA8xtn3RsM3OGBVzN3fpGvTdP0RRr8IxePz+FmWV0hPVjBKBFnEuoHnS3PvZxoXwfAS6gYR0PG6iLSOAMVCMqgjW5Khlvr+OGI3l49H4We1L3Z/iwMMZxETq6aFZyo0XDuMM+L7tnGb2W+M5dHxF8EMrEYz33N4vtegte8DzufFSQtMKGC2cRNun9mD76tURWgwDyVHsmSrZrH4OfdqbRGc+IYupAuukDrdzu8VTtKvcNHtrNO+Dqg2jhv6EPscEQ/VHNAK8SndBwtVRW5wT2SDozW4Fw8c01BMdTuuxq8Q/IDwG1F5V3kNPp+M3Ope2FMJshM+d+CnikPHMPW3BmP9R7lFQbRS/KLpZYlOPnV920joHMlkRPs54HTBbj9nUotDvBwl6EuTyS67KN5Jb0KFzJpjc066qTYu/PkPsniSJsidfelRZMMHdJQlQzaMDfkNsgywFERCs62MlC7B65cgVeJSW096hX4QG/lzwhe4FRtfG8mizD1WnW+tDA8SV30EGOegswPJ41aKJ9KLGsPoVL60ZykeAzkduWaMy75erSwl1C41UbGWhEORFhjWg0BfcM1XN6kAkMTPaELQiz7brBbNEmwqCu0bFkzdFc/dpm8ttUasiJ6Fu1e+KnH3pndD9yKc1+te7PzIEfPgEYWAllUUw0lIMHRrJXfUz/kDFrf/0rYokMSNaKqJO5ShimJ2vE8ImhAPy8oCy8+xCesGrnzIVWR1QNmpMEpZhft59KTUxvcyglcn0l2WsLJV+iYPM2mEcn3KrOlG/IEAZ2IaezMN8Y6hqivjVrZ7VC8hqhQQ7kIyVrFLQOgbZmMH8+u5Mb+KFPge3/BuKtfh5uEFxcDmxeOC7BGRBLNXdGq/U8x7jc9+Hk+xYKkuyucFm5dyJ4VkH1qWZQP5PWKm1xmGU0+9DEGx+ld0P2GdoU3yoPpvECSB5opIu+TgcjTOC1ixbg6xd0rdB6RJqz9s/F64k3rwVwxQxxJAcU+MadlnfF6WIsY4bghoMg+9xDthtklhmiNyMJJt8X8etLGqYttSGZWdDdgQFCb9daz/al9Sg8owETrPdJV34buHeJyMqwjLe9NJv1YB2kTIroDOZeNlGCiDNYNa3GP6yiyxbWYRgeeX0h0vsKxsVsu7flUB0fvoxHDE6H2VWRJnj+sLcmspgPFZBiPCzjW9M+0Qv5WSh6RLOFwKSckbjoDNBGR/Zf6O2KzdKDgiaCAPi1t3wqdI7Rnug5SH09jTJMJWaOkLQmWuYZ1nAPAG7h5zU/Huxz+C65PK2tIKiDiiVYopjmtPBmWU6RN4nVv6T0XTI7gaIjBai03mgYUoKRFNbXeb0eT6Y7xA==","layer_level":2},{"id":"a17f3c03-ab3a-47ea-b7e2-d23375e4be7e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"任务执行与监控API","description":"api-execution","prompt":"创建任务执行与监控API的详细文档。涵盖任务执行实例的查询、日志获取、结果分析和历史记录等接口。详细描述JobExecutionController中获取实时执行状态、执行日志和检查结果的端点。说明如何通过API获取历史执行记录和质量报告。解释JobExecutionVO和JobExecutionResultVO对象的结构,包括执行时长、状态码、错误信息等字段。提供分页查询执行历史和过滤特定状态任务的示例。文档应包含性能优化建议,如日志流式传输。","parent_id":"251acb67-6d5e-45eb-b64c-94b11aa2ce30","order":5,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java,datavines-server/src/main/java/io/datavines/server/api/controller/JobHistoryExecutionController.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionVO.java,datavines-server/src/main/java/io/datavines/server/api/dto/vo/JobExecutionResultVO.java","gmt_create":"2025-12-25T23:45:58+08:00","gmt_modified":"2025-12-26T02:29:52+08:00","raw_data":"WikiEncrypted:bSHy67jikAvId3JJJ2s/CaAKgWYQMIVxd/bBB+FiHB4y1qXEgc5tWaPumJNPCFKK3xIE7vK/IXGk41/xuL3TE3PjpKJDJKZOjrZo1RxKNyJuelnFTveAa2ZNXg4rp+epz1MDJHA3+9YhSEIPCp4ZKK9oyaPORQ8oXs7lRaQkmEXl0zEMIL2XNJZP2GecKB6fwQAkRZBTvpMdRr/tgs2KpD+afs+q8T9J3nkg3T2MB8ZjL7R5bB1hW/9j+XZKO/KA5swZUM6Xzh7hPdpo2VTC0OSO5iUAfpvRBqX85XetX6FDPKWsfzvBx9NeU4SRe9amNfex3cFp3ffoYD91jDKgHOBiEBpI8ggqpliGqVhyT3cJ7cM+G/ZrJ7M9ig6m/yIeJx2obdFAgwy/YhsT39IyfgdeoeAhvxITrt1OwlB76yeNHCZ0hvgkxct2ufG9uTfVZUaBpIUukNz8/rxu8wXctqbROjUWWEkW8H3I8BIZEtezyDfZqKa5p+NWWnjpzwa8eFY273Kns0ETDj7e6hvmBXnQ7404oiCK7QctScYpnBIYwZNpGAGc5F30CuySPhqkcZDXib/hLCV4ov3jnkZ1MHC5WDZkrF++GanP/ZFC6nAZgGGxAN18/h0WDhX7wVcUWiSh21xWAp/4a1nN6/FwQUERibnvwHdEnaKPnUnkGML2ONcnjjOMdwsX5U+vr1dUNxf3jf+mLRYwLeQdaL3hKyhW1gsyBRmjdEBSjNCD+84ClFYJ/wxk7NmseRWKgxy14OHsiZo2PoROklidArSJLRb+Fy1DWWwhmH3tD5mzsR1V3NUGpgaUQ1guFJUDFmzYaTdyAEo7UJo4Uh8dBgFPwQeOD+jevskT78xrRy0DBqE4Rs6uIRX8l7pQp6yRFdCblf3wVNSDCsNU8p4G1bUCGZaVPI21IZ9DYPGGANTMldVaPEVwG73tHAFeUaE0Wbi5QHm5grBrOLiVHAg5vLUOLNnayz18i7QU5domtspDGIQ6Ggyiikf4x8rTpKsnoTJFCw+l8LXEFvrOKAzjl912oyWnKr69/Xh/ZqudtwM2oSTM2Ffm5YzWyNxvQwEtsqwjMSaSxFPVPLr3kwkRJY7gXvOchcPOWJtO8/FAWdOibIgkyBI/dcsCKp34TAH0QtZhuIHk8cH1h3ia6sN2SvHKnk5KGWCMP279a/IXOMYNA3C2yBWQa7gZ2mmu18eRX5UtnXFYjWN5vfon0CGW1fwUZLLktyX7cLPtI/Leum0mlI2Hz3ghpVOpexo9d4UfPsyNxyP3Tbcukm/cEs6LHSh3Hmee5Onoxh9QWoMTBpALYdIpXwxd2aoEc9PWnYQ+UrW2GuKMCBsYY/U4okcHtYDn62mP/djadXK8z3O3oCbpwOrti/nI6IwKE2xOZrfagS4C5AE6EjiWPMNDAziCA7FMbFQDiVw+8i5wv8VDYsRkEGoXqsTmfjR0FsFsOAxgsny5zSL2H8kcr3WNoteoo1hYssxRWGyCqfXBKLnrBvfd0xc=","layer_level":3},{"id":"b4082be3-2f3e-42dd-89fa-9295da3c62a6","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"API参考","description":"api-reference","prompt":"创建API参考文档,全面记录DataVines提供的所有RESTful API接口。为每个API端点提供详细的文档,包括HTTP方法、URL路径、请求参数、请求体结构、响应格式和状态码。使用OpenAPI/Swagger规范描述API契约。提供实际的请求和响应示例。解释认证和授权机制,包括token管理和权限控制。文档化API版本策略和向后兼容性保证。包含错误处理模式和常见错误代码的解释。为开发者提供API使用示例和客户端开发指导。","order":6,"progress_status":"completed","dependent_files":"datavines-server/src/main/java/io/datavines/server/api/controller/DataSourceController.java,datavines-server/src/main/java/io/datavines/server/api/controller/JobController.java,datavines-server/src/main/java/io/datavines/server/api/controller/JobExecutionController.java,datavines-server/src/main/java/io/datavines/server/api/controller/UserController.java,datavines-server/src/main/java/io/datavines/server/api/controller/WorkSpaceController.java","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-25T23:53:58+08:00","raw_data":"WikiEncrypted:C34GewOyK1SlumqKiPsSg+WPNa2UHH7yP2PPjE4/OPkUytUlTK+XtmhJqDmkbtEHfaHtAAX8Q2efDh3FbIUoCvuHmoAlo7EEx4HQGX+/y/1phhp9GYH18soqy86MLAZG3k5BEpgqxT4ib1Fi5BKZqZdNrCS9b/lU15RBxQW9bnLS8hLxgIc3KRdUxXujdobqvpA0UskTEoSG4b+SnnKAjn4dFVlaUCNSWCSjvp2LXAXIfGWCqXkkj84euSSSmcUg50H34XL0FZxK9dRKUlpoyolt4FJgzvO+/4EHfmV5WOsVKSH1cyu0BgO3T2qa00bsQaD6aUs0/Ka1ys8yH6XO5nZSUYr9mZAGUwqMnlypQNiyLJ/ChX1mKPJxp52JQKMyxjDiY77yjNcqv/gS+346wk4KygzaQ9RwJjF5MB9sf1ZxAUC4D53OWk1w5h4ywC1KuLEFZc6QvN60smzKxPwVpFFhgbfTQErxIYEiFIj+jOqF+f6jhdojLaFuCS4MjWriSWla1ZGsUVSZAnYMmgVQMRAlPREfoGDMsQsJKZClC8TqLwrM0rZzpd0X8dKDeaTg8o2W6fg8JjfalAlVkDSc3t1HPYvzPetQtjM+FmcjBrxdYS6h1uqDuIil5qLoHnhPwF7BCdbHrUH+xdIr0PRhZ9V5Y479yGsdmqqEI3NcKsco2/VHW1iSczmhs/jOqpVrujfaTp1Kg8M2MRE5azK6aX++9xSUyUiaWLmHivL+OOtHnGzohBoHSu0FEKNfXaavVGEGVMtxCZtVD889mRB4OLxcQ3Eb3yMZp2/piHAdFuUthuGPKLvkMLyrIH+NcQ5L3QJhWNy35CRlVhab2uXDJ4YUL2ZhMMGqAbIjH0I0bAa3MZpcQzVPR5ZNJhzNHzIa0R65NDo0IOkjCQzN3Qjai4gZgJK7TGBDz5LYqB2QlhwbkU8DMTKPmhqc0puncPWIDNWjdTaztiOJFKQmmBTftt+RvoU+ArvLibijF3R2silreX0Av4+CTcgVNAAsZS2YacqjgE3UoveOFaZ5QVPOXcDqzElZw55yNjxdV5v/FdJmh/IND5A66wBFtK1YIs9/piAnezNtPtuPNHIf1HRy2sbc0FMSizfPBmXIFgK2++W7oHrVVJu+BSUcptwHiPPeuFQmRyPpKR4tJEVI1SQoMHApLNpO+rbkJLxlK0GwGtx3AJf8P3tq6lEJz5OA1Gnf/g4InjSOyOx2IWcWi8kUoij7xh8n/Fj1pZoxe+GQjUSPtn9xL30DNbWSnhncB084vEBxZhKvJr0Git5VCwzMQXnwVuIIjxugr9iqB+6Sh3GEWArlshG1+FiTSdFTZod9Ieti0em4xtHB/7VBkJLALzkdgAi+nWE4WD6d9OLTPZKPb8wvwwQtlECNV+NyDU/pAbOIeMdOMCQbCbZ6teGMoKdulHvRAta8Llro0DGOa/KMS58RE4M11lwfWEAhhSOc1z1nzNIttYjo6T0RcLwbFV/NG/v6f+f1ALE7k+BDYY4trpPInhoZ2rQuTmm/ZjBTk/QtMIuHQ0pRb0YanmJEXkeNDiaG674Z6vk1QGAnhRFW1at3bqWQ/kFyJ3mJuW9+Ip30p0Q3aJwXYZ8lAg9vZeUc4p/HZaF+zfSs1pX2rBQ="},{"id":"f6fd9d61-f5fe-4cee-a269-b29ba2583618","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"datavines-ui模块","description":"ui-module","prompt":"创建datavines-ui模块的详细文档。解释该模块作为前端用户界面的作用,包括React组件架构、路由管理、状态管理和API交互。详细描述主要页面(数据源管理、任务配置、执行监控、质量报告)的布局和功能。分析Ant Design组件的使用方式和自定义主题配置。提供前端开发环境搭建、构建部署和自定义UI组件的开发指南。包含性能优化和用户体验改进的最佳实践。","parent_id":"c391a73d-20a9-4e3e-b13d-54fba38ef59d","order":6,"progress_status":"completed","dependent_files":"datavines-ui/package.json,datavines-ui/src/App/index.tsx,datavines-ui/src/view/Main/Home/index.tsx,datavines-ui/src/component/Menu/MenuAside/index.tsx,datavines-ui/src/http/index.ts","gmt_create":"2025-12-25T23:41:22+08:00","gmt_modified":"2025-12-26T00:32:53+08:00","raw_data":"WikiEncrypted:McplZCfHB1R9m7hJ42GZxncRGiSOgOsKSIGdMsb/PgMtnn/sqiLfofaph2FIxkTBUS4s6US4sZSSeHGUQlmKEdPUSoE7wjXkSPBhDboFUMr0i0sxd188tHwDVBHNQEgJO3mcMb/qWgfi2gtKeUqsVf97gQY94Cjt1ORrQxrmtQsXzmtn7nGPiDTEi4jdFeljoPdTL1ECnh/j7dByekRIcsFnNoPbOmlfZgv8w5RJKdxaSW1ztU24Ywt1xHSKLLgxi99PBSkES0zsvq94cWkH4t8mX7PtyQ6ZhI0GcAng7kRco28tNYrvpoXoaHWrAocrBvRz+cgfbfLHhZ1lpin4eIAz8I4pDl96f35GPeFcqiup4voblRf7uxhw0MlfKTrExLIjjX/8/sVZBPwqILRHhYR8bCrSXRtib8sk7hTiRty+5neI2mJZz9yMsysdZRBn0imrw8KE+i70lc6zMn9JArUv88TAgVWQoRocZsy1sV32msqViXrvS7vVRmb8KVZNjLTD2TdjLxIFsGoQDTy9q/Q9rIiQAyH1cHnDWEWh5U5+jGj1VfPO4E1b9uC49NRE9necD6YItTtFLXMibTtfYjRLSNZ+Q/nsvRXmNCPxxSPx3PrLxvYFI4AVkvgsFelp/U+HpaZZIK72AG8BAjQ1qceSoC0nMC1/9E3UFMLu7XzMFtfgDdh77n5tGonqYcg80wkSG9c/CxiS+i8vms6Sb6juyMtZ3twUSQp9N9MwuPXg83o68TNpe5M/5JZ0KfT1fcjQqmjxMgZosM3X5iYwmnmcjjFV1Iy9b5TGfWSqY1kwlOwVblYXUlMHtZiJ6FcdduCDBdrFRw4eBX4yhzn62EgtM9DiHNMDzX47M1QU8qRHFuama9hsKth24egQPDbHorUUmqKmeaMs8GiLjpo9Rq7Zga3LuXDbrNZLN/Qn8kJksb68tA3LUzlvf86gskMLuvh+vgQp5+8rfXp4K1xc2jxIi4gAMV7COy2L9fYZ2l4wDvIRALN9eVf3qMSrQzdhDdy6Fw2Jx6T298QueVKYY6dBMIYELlTv10UoyneTIxX8guSmMm0OKtc4w8a6uPUJyR4EZyx/eijhx7XmImBt1BJTh1oX9hVlTjm45KQDgLEerc3jN6XLP4TcVYn3diO6ISXegLYNvv7v/10e2dD10x9X/WGmc38WPTToG2y592GB87f1DNhYq+rYg4h+MnDS","layer_level":1},{"id":"e2c0779e-bb1b-4aea-bacd-3677c0c70053","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"Doris连接器","description":"doris-connector","parent_id":"e4bd9d6a-26b3-44a7-957d-46e0c9ba5cd7","order":6,"progress_status":"completed","dependent_files":"datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnector.java,datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisDataSourceInfo.java,datavines-connector/datavines-connector-plugins/datavines-connector-doris/src/main/java/io/datavines/connector/plugin/DorisConnectorFactory.java","gmt_create":"2026-01-29T21:49:22.0606857+08:00","gmt_modified":"2026-01-29T21:51:04.681309+08:00","raw_data":"WikiEncrypted:oDEFYxyjDD1GabGsl2IZCpD3h0ApOdzLRiFfWkaAuYKLBc0SKaXi1Z3Ijbd7K1CKvMyekPUagrEJhSEZwIF2t77yLqjuSX0ltAbhbIpiam47KzHbAjy5YXJEszq6erOD5zgugwGLY++73fSFN199bd5HN80PzyBedz1vu2OQrnDM++ye0cAPu7BKaD7mzXx64kvrkqP3EBQlD6GPURNi2BJt1t02uYg4Kud3NY/plzACC27GvEDeglBZDu+eowihBpP8tqDaCdUDVCNU3IBD6N20u9OnrjFy7hqSClzg5At7utlPUW3G9vG32KG7hVy/tNCmxCcVeWCrw/VQQvru1Uce8e+F6oDaucPwV4+pgPH1f3DB5r8a/2622Ax0DcZ0TrDHJqEeVWGhCC+us4omnCUa68EUBYZrrO9N9OQBkfs5aJOxXTxngmdzvfWfn8yUkzDyVSif09n0m9O4bcXTcc+Sp+oIRDoL38SJIdv96P8lZ5jUR2ZIMmNpQIcu9JuF5vFsaJeqccTLKr6ftanAhaqvt13/c5nJ6yD0AnOJIYxQ4ZODEpHTIuJgIyCA14S08T+mSoR70hliKe53TUZkAyCtLVWURQv6B+roX9iqAJjI4i9Yr0+mczJdhn17EWam1Q55sL5WhvNr5EM+1kO8j7LFAfVapjuBd3LLn2RNP26LowfEruN0cHno9DVWvQgaMbp8HRXx1Q5Ie2+J0j2zIdDx+g/3VALh07q9oTp9HKc=","layer_level":2},{"id":"a5e4da90-df85-444b-85e1-80088657b90e","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"部署指南","description":"deployment-guide","prompt":"开发部署指南,详细介绍DataVines的各种部署方式。涵盖单机部署、Docker部署、Docker Compose部署和Kubernetes部署的完整步骤。提供每种部署方式的优缺点和适用场景分析。包含生产环境部署的最佳实践,如高可用配置、负载均衡和故障转移。提供资源需求估算和性能调优建议。详细说明配置文件的修改方法和关键参数的含义。包含部署后的验证步骤和健康检查方法。为运维人员提供监控和日志管理的指导。","order":7,"progress_status":"completed","dependent_files":"deploy/docker/Dockerfile,deploy/compose/docker-compose.yaml,deploy/k8s/datavines.yaml,datavines-dist/src/main/assembly/datavines-bin.xml,bin/datavines-daemon.sh","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-25T23:55:31+08:00","raw_data":"WikiEncrypted:0IKfLNOWe9mZfG1jVts3wxq1Ie83+Lf6EMuycQSN7s3NFV5ooa3Scq2B9C67gTKq2J61WmIo8uwzopEI3o+rx6Ow/OhddhpIB9b1gQWJ2PzxhPb8oYiirHd24C3u8yFbPlQeI78w6123bTdvxhL7xFz1dwxbPk5w0Md/673GDV0oqF7rHJJXu/kuJ2Ee+SBuAmwkl2GNtxS0kQYS5uODLZCbKWXI4+mpYxoO/9qZfwCIaccWkjhaDZcD+IcLkho4TmkqN/yhrIrFttS4l+FKdikJqIhP27XsGFGPzdqjJY9tzBtSOeUrRLrAgDCacZm3/2IanQN0nCiqDVRIsJISQEYjVpjJ23JSgQ9RkLM6cMx/T0Zp/xbvV1yetx9XuiSP2qhQ2fTNfhhhBAFrxNh2QEAi8BZ3q+L1YCsmJmbPIdPxPtWedwA8wLHdn0laUQIYpVSmyNAx81qtWFm4mh06bTmvfCzReaHPJKMKFKqW56ov10Mcp1a1p+RPHqJeSaO8g4kOaqfZ0l8xs4Ech/Gpi8kdkNtweW86SggL71/XdvGoVM+Un3+VGJh8vEpBqpofjMVUyAHqR7iX4zzypMvoNrCLFym8+XDKU7hBJdA5GFjlYBXi9jpCP5VGb49DzboCUFl5ey+urYQWICo7LSQ6MmlbhCT1cI/kbpTYvNbr4Kd2XY7P1DZlkoLwH47eWTzn7H/q4lziiq4REtyh33FGpL/QWuS5xOoce+NREmZwBuxL+fp2LkdJ6GRb9wBbSOgmBIwRl2D+uUy7QPx70yWFrO614q/ZORXLv3WjdkX9/a3S/YVfcVeOtfllrXdWm2WdqI3ItW5kcyPljx19i5t0eC9v+VIejjX/84/3Rp37bbZwpvDjSe1VM3Lo0utuG5bS9OQvVbG3CnT0p6K6V/TlfS1OgB9jo0q+MM1LbjZLZ1dNJX2vjxedH5usviYmHFPjIH5dMvQtUF56XBLjJ3Qk6Zcl5DESz9f7F+dt+kFfXTSnMK+81KP1XULaMfT5X6srZXQeuC019g0LjhijazsLklqZHjlGJQJDXJSEegV6hXIMd+iVhUp9fXBCcvueAzQ/Yor9zo9v+mKOxl0uDsCfhkWMRC6C8O4XlZh1b3gnO3V1LCIAJbhpMrMzQHnbfWkrLn5llIKyzEMms1irlzUS5MGc11SObEVkCFsUacCOzkDEnOpSeIQOLD31fsaRVoGzfJWYbOkUS/q1/Dme6bVr9ofscGvlRtzs8oW8RdtQdJJbsOJP1U/5mhwHd89Tu3fJznkCMrOW4ehgnrsjEVGUUw=="},{"id":"5d2798df-80b4-4ceb-b66b-9167054fa556","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"配置说明","description":"configuration-guide","prompt":"创建配置说明文档,全面介绍DataVines的所有配置选项。按模块组织配置项,包括服务器配置、数据库配置、执行引擎配置、通知配置等。为每个配置项提供详细的说明,包括其作用、可选值、默认值和影响范围。解释配置文件的加载顺序和优先级规则。提供配置的最佳实践和常见配置模式。包含敏感信息(如密码)的安全存储建议。为高级用户提供性能相关配置的调优指导。确保文档能够帮助用户根据具体需求正确配置系统。","order":8,"progress_status":"completed","dependent_files":"datavines-server/src/main/resources/application.yaml,datavines-common/src/main/resources/common.properties,datavines-engine-config/src/main/java/io/datavines/engine/config/DataVinesConfigurationManager.java,datavines-core/src/main/java/io/datavines/core/constant/DataVinesConstants.java","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-25T23:55:15+08:00","raw_data":"WikiEncrypted:aC5ZtUyEKPSxjzg//aVllG3KeKoHrt3VUYbwJdfZuc3qnb3DDIDoCMLZ+0FJAn1Zw6DMt0OadJXzQ5qMudyp6+ru2QAhmxA7ooTz4rIQbGA9xJ+8IODseOGCTJnsyldY6S/kp9ZX16+22dPWgGwI8gkj4Rx6HKV55BiXPjvqlm2Ze9ZVNWXO8hKJsjJ6jJh0JzMWr4bd8iI84gA3m8btZP5CAlVcduhScmmPMwypXMERdpOam+4bXPTNY4Mq4et+jfSUZvG2ssuGcisjvFweWZsXQ6R5geKROWoFlEKR/BclV40UV5OsNItCmkAmNn76MMZDEsYlH8dYIUnIrFQzjaYBjokAkUTfajgztiGJ30FX0og/ZIHaRy1dJ9ozzsCWOxen2KukFCIquVgLrwJSaLaFyL++E3QFb3bWPoQXMRHHTrFs7xpaBahxceJ7f5kM7gh3m6/XLNZqFcF3aypjVcbIs9UmbBJ/rAQVrwm3tKFCBmwUy/AihFx89ygeXeILqhlBCxTUU/oBhTdXBqrbjTaAX/l6UXgt8B40OjMsRw74RWMA2Bx68ETMtl4P/zgsK2ygrL4K64GK+O9GNSHYZkBc/4Iq9zm8I9EYPGWncm/7/hCCSjy5SRmlaT1UMgOD/Mud5sHI0t48WAy5XnX5GY7fcSm/AbJ0/Knm8YBJ0JiAlNUSr7AsqrX0ZiwyjYT3SV4Ye9x8IsTFjXW8ZsHAkU8AU/86FdfltADfsYOfM7yNplJ8mwSoKZQpzgv44xmCIj0R/yPdkB6d5KyGEsm+9a+SI1luiY1MbH9/lbLuR/DoJmyPo8zEeLZNW9uC6Htivn1Tkhsi56Pu7d7Rdcb1iSWL8QSkctSv0qq5MIa/F2ahgrCfmUfmq4IBB/7sTIyWGu4bPRJ0D4JVsIeBKOG2Yj6zsZAaijyoHMcrjLLyQKOZ96t0RRoV1d2X+DDeMDWWy9W2FT0zCca8evQLg8ek2B0fCOWNBFc7UI0f4Ef9El3aD9VXH2vd0e6D6c6exc98KarBnKKfRX1Ttu495ZxfgBGuQ8lWi+Km6XQF6jIaNx7tJEI7UFajfUFWIIZcDxNJeqWNqTV+bdbkT2OHCT4TxKPKvkqGrxW0ocSB33et1I6ZuA9s8PqVDQXAfw2XPoh2ce353EU76uaDeYhKaQtpwvVcDm7z85Gq5r11kXpTDnkAQiM/6lmRO3rhJUIH346r69EuhzRpCNAfrT/LsFsE5Dk65PxNkRbG0OAXbAAGmM8FBIsvyzdXqGQ6pGUaxbPCZIYHXjW11W13Lj+Qt9C1D/GesMEYXa7j9+XFQFlI9ugLjlN6/Ag14TUbp4HCgcr4WCcaNKWoopSahsUOc9G+B94cEdOg3sjijZhL9gGNFme9O4zV3q9lyiGTaSpJ4WWWemIlvzDpSYy9myFTvH2EYdp+GapqOghww376AHe4yeEk7bq9Bk8slGJ40NBOGF4XkNk60QQdqBlI2p+1SbNbA1bjNB/SERszs4Tz+k5ZoX8="},{"id":"1a586877-260a-4728-a2fa-ba930f91fad6","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"数据库设计","description":"database-design","prompt":"创建数据库设计文档,详细描述DataVines的数据库模式。提供完整的ER图,展示所有实体表及其关系。为每个表和字段提供详细的说明,包括数据类型、约束、索引和业务含义。解释关键表的设计考虑和优化策略。文档化数据生命周期和归档策略。提供数据库性能优化建议,如查询优化和索引策略。包含数据库迁移和版本管理的方法。为数据库管理员提供维护和监控的指导。","order":9,"progress_status":"completed","dependent_files":"scripts/sql/datavines-mysql.sql,datavines-server/src/main/java/io/datavines/server/repository/entity/DataSource.java,datavines-server/src/main/java/io/datavines/server/repository/entity/Job.java,datavines-server/src/main/java/io/datavines/server/repository/entity/JobExecution.java,datavines-server/src/main/resources/mapper/DataSourceMapper.xml","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-26T00:13:13+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkBwdhOAmcMQTz+AJLOFORhNFeFTAN7xitXLxeRr3T1sKrh0z/6NFLuxfhi+XJSCnWrF9sPBINWn3OuQxO3ffCaG0LFhSa4G4JdglvSgRHU2rNPPCKY+R2ovB0+qYjI6m+2fMEJUvaSobRXqdqm4RLFU8GSucOgjwss8BGydbBrS0yu+CDrRSnwxiRLxyGj9uQ3OYfiacN52sbkQFs5PTJdM10flFCQEKDU6QXA4m3Blfhvr7YUVHlfkvCfi2VhuNU1idCQHDO2PQIrrwyWXQRFqFOODEhQHjpi+ytYjKvxHlvWQZvJ29MI2fQaBU7+nGFNySf1jompFInyTW2kM6ZVoHxZNUNhnyqMAsax8PhZHvHdKcYADYDeVPPYhLw88OJd67XZj1BFPVLJj5YoYUIkQs8Uc8LY90lgxLUaJrTrYPFEiF20DzT+LSe+E8aklCtIvS4VrD+k+7RkmWYQpdxKdx9o7BiR2+AFbYfhriuSPNbnsF7QjRTr8x21pyHtUptDrQH5x7dJBSCTlloeB3nzFKdSuenQMS2nikC1XGDDl1e2zO3mXzm0pjLS7NeWfhWHWCOt0IwjKXDp1T6v6m4/HjO3LrUA4jeqBJDynmYCR2SAxGHq5xU5PBQ0F0zsYErik0QfH3nySvSTTmHJkEukLmqTk8sH41iYRxt/9U0CYfW3UBanTG8anQ//hsgh7ldosWqqTvcB6zcdBIPq/608CHmKvYIYieyM2DeQxjuECG6QQ9x4seg1oDj3P0lyxvGNL0TOoj9OHSAGATE0hDVblwYQbG214FxC2+I3OQnN576Yx37JvDP8abS0ljvLSKyUGnWgsxWRzkTBPM567VJMh0SiTnSIpba/P5P5/IqK+beR3e22qlGyLXiOtCumQjSV5L2HFBN3nU9kEUCzj6FSZL3ogvOnpp7hfKkwUlowxt59VY4ihEw022JuSi+DYMTvqr10BC8fq273sbQzDAJkRmsU13aMD9T+7SywDKGpMzhS9pMSsbez4TNVOJaeuj4m5dRUTGE1rSJk/d5Q5wZ+oAlUsaWs6yZU5a2aSepcZcBEWSE0XpNjgQkOym87xwS345nKBEIizawMqz/IqH0OgNov0Zzrt8+C7ZpYH0PUVAWWPT4GHJU05Ell6IafZL7tVh+DwL42bgBgMzrvrqO/hwWmM2RAsDLgyt1VVP5zWCsh7lQZZSePrDB8yQjL98pPiCYZYqrWEmOwJi29u9ynn7xZoBSFYb8+1x6rkkiENNfcdX3O4BvYqZnf1iVi94HzWhSrcJC9fk08n+29p1DMooFn19u3npfOOwjaXYE/qoXq8WQ8YxQhD9KSMGXYQ0ABGc34jQmRaz7Q+MR8odYb7BJ2OIL1NnIP7sDUx5hTFY7AbrHel/6InH3tlOI6BWvTj9jQcxmWv/D+9c4Izkkywps8AMtc6E9h/8Qk5tDKan"},{"id":"9c9ea581-96f0-4d6b-b268-df0c9ebb9fe6","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"开发者指南","description":"developer-guide","prompt":"开发开发者指南,为贡献代码的开发者提供全面的指导。涵盖开发环境搭建、代码风格、单元测试、集成测试和代码提交流程。解释项目的构建系统(Maven)和依赖管理。提供代码审查标准和最佳实践。包含调试技巧和性能分析方法。文档化项目的分支策略和发布流程。为新贡献者提供友好的入门指导,帮助他们快速上手项目开发。","order":10,"progress_status":"completed","dependent_files":"pom.xml,mvnw,tools/checkstyle/checkStyle.xml,README.md,.gitignore","gmt_create":"2025-12-25T23:40:40+08:00","gmt_modified":"2025-12-25T23:57:02+08:00","raw_data":"WikiEncrypted:F3QgleoEfoy16cQggYe9C5IaSqlGa9MAZLOFAWytoRMydW9CaKFacxmHFMFvq4MO4qJbomNzYz9hncXLdeBzq7rIrLOezeYVED4iSmUWzqZNsjCmWxOU16/qqRMUkkMUuroHYHe/X0LqasX7BeL2FKH6QyDXB8WJFNcmTvQUvKpD1Lw5tHcutZ3NfE8+V3KX+nczWqPwwC2UFBL114V5YXKUf5gcbctjv9/a+9zRSgpvhZ5JMFUxTeFuKn6YJCJE8qRJfDC32iMj1UE9BbUACvgSs7LwARHNz/faeulOFBxv/4JndFczhBEoO5EWEf/Dqyvx6YAoTEPOvaS44wZ4Ei651D8fU/xa1wWrKBqTP1kvJFtzLDgV4dZ7uqe4tO86+t9/58GdW9OcimOj64LsE/9MxpOLiHuLSrGZ8FsqBx6zKVi8g+0d7LdiblF/h6afpRLaoO8sXOu//2bf8KeIf29EzFoMxJFM3KtB6CmS6kGe9ObJ9hOFfZlw/V8gbxAgYdYfCX7mKWtaNuwv7iBWTN8lBowZ0ggl5Kw6wAye9oUvIiHB1x2sf0b08IZQQMt9OoYQrlbSw4y/yPp+GOsZ8YNe0OgtaPqwxQJhJRK4WjxobmJB7GSJcRF0Z4qbo5oIpyFACQkS7+m/7PRVulVd0PpDdzZeY2ohqEtNpTgc/Y1blZxVXZ73lTAG6ykJ/n16f73hkLLz0DSj00QwHpoNB6yeeM4O8iA00um5dzdUIGEYnVVjq3NpQStM64aA94FvuGcg3ZCzuhP1oBy3iyS+rZdJ23qPTzck3od5T26baVyynGx8ljutr7UVZKnEVPKLcC/wt2Rl6yHeSOBdSihu80CQZjhTFS9ZtqlRk9dcjR2ubu0jwV+MHnBoY/lO+YwX/IXMngBTt5WqG1m2L01k0O/S+J61iJY22Kq22Sp8OsqSFcynIZGZzDIQOEL/wsz1iMBqQNDC51PYscLau+ao+w=="}],"wiki_items":[{"catalog_id":"401be447-6b3e-436c-8d7e-a0845a921e20","title":"架构设计","description":"architecture-design","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b0df0e39-2431-4b39-b088-89a48f0ecb28","gmt_create":"2025-12-25T23:49:34+08:00","gmt_modified":"2025-12-25T23:49:34+08:00"},{"catalog_id":"4b2293e2-2fb0-4953-90ce-d1ca86762e3b","title":"项目概述","description":"project-overview","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"8ae5bcfd-8532-4f22-a653-829aedd6097d","gmt_create":"2025-12-25T23:49:38+08:00","gmt_modified":"2025-12-25T23:49:38+08:00"},{"catalog_id":"c391a73d-20a9-4e3e-b13d-54fba38ef59d","title":"模块详解","description":"module-details","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d50d63e5-3a8f-4a16-8d03-e59d23082f71","gmt_create":"2025-12-25T23:51:04+08:00","gmt_modified":"2025-12-25T23:51:04+08:00"},{"catalog_id":"68f6e22d-b8a3-4a52-90f3-e23d8a3f0f4a","title":"核心功能","description":"core-features","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"6bf414f3-9d02-4d7a-aea2-53c73bca4e06","gmt_create":"2025-12-25T23:51:28+08:00","gmt_modified":"2025-12-25T23:51:28+08:00"},{"catalog_id":"f7482163-91b0-43ed-b702-cebf50029b91","title":"插件开发","description":"plugin-development","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b3dec9f6-4de5-4825-b008-9dad708eddee","gmt_create":"2025-12-25T23:52:41+08:00","gmt_modified":"2025-12-25T23:52:41+08:00"},{"catalog_id":"b4082be3-2f3e-42dd-89fa-9295da3c62a6","title":"API参考","description":"api-reference","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a8bc817f-96f5-400b-a9c9-8cd17a45753e","gmt_create":"2025-12-25T23:53:58+08:00","gmt_modified":"2025-12-25T23:53:58+08:00"},{"catalog_id":"5d2798df-80b4-4ceb-b66b-9167054fa556","title":"配置说明","description":"configuration-guide","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"13baf602-8637-4c51-92f1-25bbcbb79482","gmt_create":"2025-12-25T23:55:15+08:00","gmt_modified":"2025-12-25T23:55:15+08:00"},{"catalog_id":"a5e4da90-df85-444b-85e1-80088657b90e","title":"部署指南","description":"deployment-guide","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d79ed45b-d152-4c64-a634-4f57dbce5c7e","gmt_create":"2025-12-25T23:55:31+08:00","gmt_modified":"2025-12-25T23:55:31+08:00"},{"catalog_id":"9c9ea581-96f0-4d6b-b268-df0c9ebb9fe6","title":"开发者指南","description":"developer-guide","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"dc346331-0a87-4b1e-be63-83a0723b8440","gmt_create":"2025-12-25T23:57:02+08:00","gmt_modified":"2025-12-25T23:57:02+08:00"},{"catalog_id":"4bef343b-e06f-4b02-9a82-ced169b015ee","title":"数据目录","description":"data-catalog","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"cbb42b6e-b7b1-4826-b4d2-d027e2f67605","gmt_create":"2025-12-25T23:58:50+08:00","gmt_modified":"2025-12-25T23:58:50+08:00"},{"catalog_id":"7b49efc1-5641-4ed2-84ce-ead796da0963","title":"核心架构","description":"core-architecture","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ac2110cd-0960-4312-addd-3ab1ecbbd2f8","gmt_create":"2025-12-26T00:01:21+08:00","gmt_modified":"2025-12-26T00:01:21+08:00"},{"catalog_id":"6f063aa0-15d9-4271-80a9-edc58df4f3ac","title":"datavines-server模块","description":"server-module","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0eefe69b-2f6c-475e-898c-1e0cc92580fc","gmt_create":"2025-12-26T00:02:37+08:00","gmt_modified":"2025-12-26T00:02:37+08:00"},{"catalog_id":"738d18c8-4d67-480f-b648-5c3e57f6b673","title":"数据源插件开发","description":"data-source-plugin","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"df2be99f-e3e1-4868-9a5e-299481db7fda","gmt_create":"2025-12-26T00:05:36+08:00","gmt_modified":"2025-12-26T00:05:36+08:00"},{"catalog_id":"42719ba6-34e3-460c-be4d-a2d8a92e70a7","title":"数据源API","description":"data-source-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"612f25fc-f152-48f9-a992-c650a00573aa","gmt_create":"2025-12-26T00:07:18+08:00","gmt_modified":"2026-02-05T02:06:49.3519656+08:00"},{"catalog_id":"3523e162-52d7-4f18-aa7c-94ebdec4df38","title":"本地部署","description":"local-deployment","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3c8a2b52-48dc-4d07-ad73-21ccb25d802b","gmt_create":"2025-12-26T00:09:03+08:00","gmt_modified":"2025-12-26T00:09:03+08:00"},{"catalog_id":"19ff2e79-166d-4a1f-96e3-229b9d78a6af","title":"快速入门","description":"getting-started","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"50e0d4af-5159-4eb9-8f83-1c9d275e808e","gmt_create":"2025-12-26T00:11:54+08:00","gmt_modified":"2025-12-26T00:11:54+08:00"},{"catalog_id":"8f3493d0-b938-4c7a-8583-86ad21b282e7","title":"ER图","description":"er-diagram","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"285a47d3-4238-4eb3-af06-601a74713b41","gmt_create":"2025-12-26T00:11:59+08:00","gmt_modified":"2025-12-26T00:11:59+08:00"},{"catalog_id":"1a586877-260a-4728-a2fa-ba930f91fad6","title":"数据库设计","description":"database-design","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b43aa946-6bd8-4b94-a366-7b99f7566ca5","gmt_create":"2025-12-26T00:13:13+08:00","gmt_modified":"2025-12-26T00:13:13+08:00"},{"catalog_id":"4e0ed203-0047-4f0e-b2d9-d7fa1cf34621","title":"数据流设计","description":"data-flow","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"fbafebaa-f8fe-4bc6-81b2-d1213e01488d","gmt_create":"2025-12-26T00:14:37+08:00","gmt_modified":"2025-12-26T00:14:37+08:00"},{"catalog_id":"d6d39194-b46b-450a-9e23-15374a060630","title":"服务器配置","description":"server-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3472a28e-5ec7-467d-a9a1-6b9ee9048f25","gmt_create":"2025-12-26T00:14:41+08:00","gmt_modified":"2025-12-26T00:14:41+08:00"},{"catalog_id":"a19e7b20-774f-4c69-a930-24d3fbcd2f0a","title":"数据质量","description":"data-quality","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"306a8ebd-014f-4c6a-974a-7f77a567169a","gmt_create":"2025-12-26T00:15:10+08:00","gmt_modified":"2025-12-26T00:15:10+08:00"},{"catalog_id":"bdbc7ff1-6561-4953-bfe0-96e43c8b3e3b","title":"datavines-engine模块","description":"engine-module","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b12680e1-7a47-4deb-9e20-da52e326b2a9","gmt_create":"2025-12-26T00:15:59+08:00","gmt_modified":"2025-12-26T00:15:59+08:00"},{"catalog_id":"a852cf8a-c040-4da2-8fba-59374cd92ac3","title":"检查规则插件开发","description":"metric-plugin","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e4b9927b-7ccf-49a0-aa45-e971ba14af22","gmt_create":"2025-12-26T00:16:22+08:00","gmt_modified":"2025-12-26T00:16:22+08:00"},{"catalog_id":"9894253d-03a2-4203-b66b-195226043287","title":"Docker部署","description":"docker-deployment","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"bdb0ca87-0492-4589-9586-aac561342153","gmt_create":"2025-12-26T00:17:04+08:00","gmt_modified":"2025-12-26T00:17:04+08:00"},{"catalog_id":"13e13644-8e2f-4f5f-aa08-89d3878d5113","title":"任务API","description":"job-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"387347fe-4237-48a8-9de1-8c8b419d5ef6","gmt_create":"2025-12-26T00:17:14+08:00","gmt_modified":"2025-12-26T00:17:14+08:00"},{"catalog_id":"74203214-3316-43ce-b2bb-545d7e140a7e","title":"数据库配置","description":"database-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"303be0ec-64a2-41d5-9125-7dd46f7fa54a","gmt_create":"2025-12-26T00:18:54+08:00","gmt_modified":"2025-12-26T00:18:54+08:00"},{"catalog_id":"43eef860-d2bc-4625-a145-101fca77c030","title":"数据画像","description":"data-profiling","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"003fa99c-2fe9-4ccf-af4d-40cd84634a20","gmt_create":"2025-12-26T00:19:06+08:00","gmt_modified":"2025-12-26T00:19:06+08:00"},{"catalog_id":"a8f7f5d5-bf23-426d-9273-02f47623381e","title":"插件机制","description":"plugin-mechanism","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"804673b7-443f-4e85-8b92-5e308209d0f5","gmt_create":"2025-12-26T00:19:40+08:00","gmt_modified":"2025-12-26T00:19:40+08:00"},{"catalog_id":"3c7fa525-a12b-4451-8146-b1bcfafe2f1e","title":"表结构说明","description":"table-structures","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"063cbaf7-e00b-4a07-a62d-df3b797bc32f","gmt_create":"2025-12-26T00:19:40+08:00","gmt_modified":"2025-12-26T00:19:40+08:00"},{"catalog_id":"5d98f3f9-508e-492f-a764-85a92d4c5c3b","title":"执行引擎插件开发","description":"engine-plugin","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"22f30c31-0e11-42d3-bab8-e31b8ff300e9","gmt_create":"2025-12-26T00:21:04+08:00","gmt_modified":"2025-12-26T00:21:04+08:00"},{"catalog_id":"c1bd61a1-afd7-4c7b-9136-b272c8038287","title":"任务执行API","description":"job-execution-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"37db11bb-2ce0-40c9-af65-2c5a1ee2bdde","gmt_create":"2025-12-26T00:21:08+08:00","gmt_modified":"2025-12-26T00:21:08+08:00"},{"catalog_id":"b50778ec-d4d7-413e-9090-8187cd6aaaef","title":"Docker Compose部署","description":"docker-compose-deployment","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ed40592f-2d32-4954-97c2-25884d935486","gmt_create":"2025-12-26T00:22:13+08:00","gmt_modified":"2025-12-26T00:22:13+08:00"},{"catalog_id":"e4bd9d6a-26b3-44a7-957d-46e0c9ba5cd7","title":"datavines-connector模块","description":"connector-module","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"93eeddb1-5a4a-4bf3-a0ff-966d57beb5da","gmt_create":"2025-12-26T00:23:05+08:00","gmt_modified":"2026-01-29T21:49:21.9742627+08:00"},{"catalog_id":"14cc37db-076b-4a7f-b521-37bfc7392126","title":"索引策略","description":"index-strategy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"eb68e142-cbc4-4cee-8e70-1895d610c66c","gmt_create":"2025-12-26T00:23:25+08:00","gmt_modified":"2025-12-26T00:23:25+08:00"},{"catalog_id":"69630b5e-3d0e-49f6-884e-8e9fe153a0ff","title":"执行引擎配置","description":"engine-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ce19faf8-ef6d-4718-82ce-772d2a15628a","gmt_create":"2025-12-26T00:23:28+08:00","gmt_modified":"2025-12-26T00:23:28+08:00"},{"catalog_id":"5856ff4f-874a-4522-87cb-4ec444ac1aaa","title":"调度机制","description":"scheduling-mechanism","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"74831571-fcde-4baf-9bc1-e6e4f3a25a3f","gmt_create":"2025-12-26T00:24:10+08:00","gmt_modified":"2025-12-26T00:24:10+08:00"},{"catalog_id":"79be2698-1734-4be6-a531-b8b79079f7d0","title":"告警通道插件开发","description":"notification-plugin","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"23f64f7d-e748-4db2-9a32-e58b874a437a","gmt_create":"2025-12-26T00:25:54+08:00","gmt_modified":"2025-12-26T00:25:54+08:00"},{"catalog_id":"7a96921f-9ee4-41b0-b41f-58237a7d7538","title":"用户API","description":"user-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a3e22b74-44ee-4f88-b6d0-d1bf700087aa","gmt_create":"2025-12-26T00:25:59+08:00","gmt_modified":"2025-12-26T00:25:59+08:00"},{"catalog_id":"e9d40891-b388-44f5-9b68-9a7b7b22c064","title":"Kubernetes部署","description":"kubernetes-deployment","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e54ee939-b8ee-4f97-b731-2e56428b4f5d","gmt_create":"2025-12-26T00:27:03+08:00","gmt_modified":"2025-12-26T00:27:03+08:00"},{"catalog_id":"63699421-4dd9-4fa5-9009-18651ca04007","title":"性能优化","description":"performance-optimization","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ba65cb6b-cfec-491c-98ae-2a74f573fcd2","gmt_create":"2025-12-26T00:27:57+08:00","gmt_modified":"2025-12-26T00:27:57+08:00"},{"catalog_id":"8938d0ac-a871-4818-9b4d-dcba6e588233","title":"通知配置","description":"notification-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"fc141673-0101-41e5-8fbd-185a232358e8","gmt_create":"2025-12-26T00:28:09+08:00","gmt_modified":"2025-12-26T00:28:09+08:00"},{"catalog_id":"706d1a2a-8449-48d8-8a21-58483495929a","title":"datavines-metric模块","description":"metric-module","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a6e195e7-dd42-43aa-abc7-67405e121060","gmt_create":"2025-12-26T00:28:11+08:00","gmt_modified":"2025-12-26T00:28:11+08:00"},{"catalog_id":"da4c595f-1508-456b-b54f-fd0b5324fa43","title":"注册中心机制","description":"registry-mechanism","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a15d849e-26b1-4748-b931-e66cd3927445","gmt_create":"2025-12-26T00:29:25+08:00","gmt_modified":"2025-12-26T00:29:25+08:00"},{"catalog_id":"9b0e5495-2217-4011-bc46-1d550de3afd9","title":"datavines-notification模块","description":"notification-module","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"c3d8eae5-592e-4859-bdc3-81f5ebeda695","gmt_create":"2025-12-26T00:29:27+08:00","gmt_modified":"2025-12-26T00:29:27+08:00"},{"catalog_id":"22e9964c-dd6d-4985-afe0-8695518abc55","title":"注册中心插件开发","description":"registry-plugin","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f75ee18b-fc66-4a0f-9ee7-866f530271cd","gmt_create":"2025-12-26T00:29:48+08:00","gmt_modified":"2025-12-26T00:29:48+08:00"},{"catalog_id":"6b9ad9ae-0d2b-4fb5-bc4f-63f4901c317a","title":"工作空间API","description":"workspace-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"9289d9a1-d1a9-451c-84e8-644917a63856","gmt_create":"2025-12-26T00:30:46+08:00","gmt_modified":"2025-12-26T00:30:46+08:00"},{"catalog_id":"b9bd5add-71cf-428d-bd70-babc4f2ae67e","title":"数据生命周期","description":"data-lifecycle","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"44d4499c-ef2d-4ff0-8606-56397e9e1315","gmt_create":"2025-12-26T00:31:02+08:00","gmt_modified":"2025-12-26T00:31:02+08:00"},{"catalog_id":"3268b632-dada-4561-a9f6-4ae317e64f29","title":"连接器配置","description":"connector-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3e4f1072-e709-4860-9a6f-6dbf5f55fc57","gmt_create":"2025-12-26T00:31:42+08:00","gmt_modified":"2026-01-29T21:48:29.3082543+08:00"},{"catalog_id":"3d9880ab-c577-445c-bb52-b4ee5d0415a0","title":"datavines-registry模块","description":"registry-module","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d2c9ad66-a827-4029-b221-942b9f1ffff2","gmt_create":"2025-12-26T00:31:58+08:00","gmt_modified":"2025-12-26T00:31:58+08:00"},{"catalog_id":"67c4da86-576b-4264-b187-42216255a143","title":"安全配置","description":"security-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0617f6de-bc78-4987-b57a-d81e6802ff10","gmt_create":"2025-12-26T00:32:53+08:00","gmt_modified":"2025-12-26T00:32:53+08:00"},{"catalog_id":"f6fd9d61-f5fe-4cee-a269-b29ba2583618","title":"datavines-ui模块","description":"ui-module","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"4568681a-4970-4d2f-86cc-330effb87a9d","gmt_create":"2025-12-26T00:32:53+08:00","gmt_modified":"2025-12-26T00:32:53+08:00"},{"catalog_id":"493d76ff-0c76-4864-9a2e-0a1aad23f133","title":"元数据管理","description":"metadata-management","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"eeeebcfe-e030-4d58-b0ad-7b86db5b5172","gmt_create":"2025-12-26T00:33:49+08:00","gmt_modified":"2025-12-26T00:33:49+08:00"},{"catalog_id":"37dbc468-ebc3-4415-b1ed-6d83eacef21b","title":"特征指标","description":"data-profiling-features","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d6686f19-13ba-4fe6-8c4e-3bf0fadd36be","gmt_create":"2025-12-26T00:34:35+08:00","gmt_modified":"2025-12-26T00:34:35+08:00"},{"catalog_id":"9b5eff2c-3130-4124-8dac-52560ca652a4","title":"检查规则","description":"data-quality-rules","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a5e589d4-d359-4c6a-937d-772308efaa81","gmt_create":"2025-12-26T00:35:05+08:00","gmt_modified":"2025-12-26T00:35:05+08:00"},{"catalog_id":"5a95842d-bb17-4f7e-b3f1-fa2cbb84163e","title":"组件职责划分","description":"component-responsibilities","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"9b2bd429-f32e-4cb5-be78-92dc13b4fa70","gmt_create":"2025-12-26T00:35:20+08:00","gmt_modified":"2025-12-26T00:35:20+08:00"},{"catalog_id":"26db8717-63bd-4666-ad5e-8d31dfd21688","title":"SPI原理","description":"spi-principle","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"19d79336-5e0d-49b5-b241-e4c9328883f6","gmt_create":"2025-12-26T00:36:19+08:00","gmt_modified":"2025-12-26T00:36:19+08:00"},{"catalog_id":"869ec0d2-5e86-4aa7-b6e1-d914bbf8ae25","title":"请求处理","description":"request-processing","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"952b9290-106c-41d2-b6cc-8b629ae6eac4","gmt_create":"2025-12-26T00:36:29+08:00","gmt_modified":"2025-12-26T00:36:29+08:00"},{"catalog_id":"22137116-d139-4038-b838-9639aee8155a","title":"Quartz调度器","description":"quartz-scheduler","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"05c734b2-50d7-4311-b474-2f45ac700f17","gmt_create":"2025-12-26T00:37:27+08:00","gmt_modified":"2025-12-26T00:37:27+08:00"},{"catalog_id":"ef047570-8c35-43f0-8ea7-de306e129b99","title":"注册中心接口设计","description":"registry-interface","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3a808174-d192-4ad6-a71b-73424d1f308b","gmt_create":"2025-12-26T00:37:32+08:00","gmt_modified":"2025-12-26T00:37:32+08:00"},{"catalog_id":"a6d66cbc-1305-4155-8e13-7c3c40ae68ba","title":"架构设计","description":"server-architecture","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"9004726b-863c-4b95-8945-0588eecef92b","gmt_create":"2025-12-26T00:38:27+08:00","gmt_modified":"2025-12-26T00:38:27+08:00"},{"catalog_id":"a9d483a9-5eee-4f59-a1f3-8126ea2604a8","title":"核心引擎","description":"engine-core","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"549d317b-d01d-4daf-b9f0-885468969f8b","gmt_create":"2025-12-26T00:39:10+08:00","gmt_modified":"2025-12-26T00:39:10+08:00"},{"catalog_id":"b75cdb0c-88b8-4bf6-977f-5fb7d26b1ea1","title":"连接器API核心","description":"connector-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3d9127ca-86f1-446d-bc7b-cf696f6c2a00","gmt_create":"2025-12-26T00:39:48+08:00","gmt_modified":"2026-02-05T02:06:44.8080247+08:00"},{"catalog_id":"8fd6b4b8-992a-4e91-84a3-3a347275a323","title":"度量API接口","description":"metric-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3735cc0b-3b69-4dcc-93e0-2ab16a38184b","gmt_create":"2025-12-26T00:40:09+08:00","gmt_modified":"2025-12-26T00:40:09+08:00"},{"catalog_id":"49a4f37b-36ea-40fb-81e0-bc990641aa44","title":"注册中心API","description":"registry-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"c942c83e-0991-46e2-9447-45813b4ffa94","gmt_create":"2025-12-26T00:40:43+08:00","gmt_modified":"2025-12-26T00:40:43+08:00"},{"catalog_id":"6c3ef1c9-0be6-4b84-8244-1c98d62e3f18","title":"通知核心","description":"notification-core","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"5275f0b0-7594-4270-ba29-3af4db57be84","gmt_create":"2025-12-26T00:41:09+08:00","gmt_modified":"2025-12-26T00:41:09+08:00"},{"catalog_id":"8812d4e3-553c-40ce-990b-af96b66c9c09","title":"任务管理API","description":"job-management-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b4875857-d9cc-4356-a846-109504feceae","gmt_create":"2025-12-26T00:41:52+08:00","gmt_modified":"2025-12-26T00:41:52+08:00"},{"catalog_id":"31124011-bb2c-4479-bbc6-005303e34f2a","title":"前端架构设计","description":"ui-architecture","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"803a3ec5-5bc3-480b-9987-da3193f9f6db","gmt_create":"2025-12-26T00:41:57+08:00","gmt_modified":"2026-02-05T02:04:47.9892261+08:00"},{"catalog_id":"8e1382cd-548b-4cf3-a8a3-e29a4289097d","title":"数据库连接配置","description":"database-connection-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1da4608c-225c-48d5-b95d-719b36016a4c","gmt_create":"2025-12-26T00:43:55+08:00","gmt_modified":"2025-12-26T00:43:55+08:00"},{"catalog_id":"9fc3338a-7ffe-4e89-9746-58390e1d7b4b","title":"基础配置","description":"server-basic-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"2eb18165-85cd-4ec3-8966-184c430fa3a7","gmt_create":"2025-12-26T00:44:02+08:00","gmt_modified":"2025-12-26T00:44:02+08:00"},{"catalog_id":"b35620b5-0643-4c61-b8b9-da5347435165","title":"数据源表 (data_source)","description":"data-source-table","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"711b6441-8164-44da-bd2f-1f55fed31484","gmt_create":"2025-12-26T00:44:15+08:00","gmt_modified":"2025-12-26T00:44:15+08:00"},{"catalog_id":"00a54051-ad41-4d82-b7af-499fa8e67486","title":"钉钉配置","description":"dingtalk-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"5deae797-c878-4f81-a762-76a5629dbce3","gmt_create":"2025-12-26T00:45:25+08:00","gmt_modified":"2025-12-26T00:45:25+08:00"},{"catalog_id":"82e5534e-5b78-4582-ba77-8590166e6cd0","title":"关系型数据库配置","description":"relational-db-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"9107bcd8-f768-4ca0-905e-34675135b448","gmt_create":"2025-12-26T00:45:42+08:00","gmt_modified":"2025-12-26T00:45:42+08:00"},{"catalog_id":"70134ca9-ea35-47db-9e54-9ee96c02f6c0","title":"本地执行配置","description":"local-execution-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"877b5a56-a3e2-40e9-ac6b-47d6b5cd4928","gmt_create":"2025-12-26T00:45:44+08:00","gmt_modified":"2025-12-26T00:45:44+08:00"},{"catalog_id":"9a060c11-69a3-4a51-9fc7-0561602d8775","title":"认证配置","description":"authentication-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"742cfe44-eb1e-4c34-98f0-b34ea70c5ee4","gmt_create":"2025-12-26T00:46:58+08:00","gmt_modified":"2025-12-26T00:46:58+08:00"},{"catalog_id":"d3911c90-857b-4391-880e-b23a3893ee7a","title":"采集配置","description":"data-profiling-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"2887e512-d32b-45b5-81fa-ee73748f8aea","gmt_create":"2025-12-26T00:47:10+08:00","gmt_modified":"2025-12-26T00:47:10+08:00"},{"catalog_id":"e0c711ae-a334-4b15-8ab6-68ea839d0842","title":"标签管理","description":"tag-management","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"9d420715-99bb-45a0-9e7f-4b662cb4ffbf","gmt_create":"2025-12-26T00:48:00+08:00","gmt_modified":"2025-12-26T00:48:00+08:00"},{"catalog_id":"9f664f1b-9947-4d3e-a6b9-ef1a47485c24","title":"执行配置","description":"data-quality-execution","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"76361208-bf89-4b44-9748-f8143863d49c","gmt_create":"2025-12-26T00:48:42+08:00","gmt_modified":"2025-12-26T00:48:42+08:00"},{"catalog_id":"42102899-382d-4ae9-98ea-ab19ba59b352","title":"组件交互模式","description":"interaction-patterns","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e4cb9c4e-b0e0-4a2e-96d7-288ea1a7ba86","gmt_create":"2025-12-26T00:48:54+08:00","gmt_modified":"2025-12-26T00:48:54+08:00"},{"catalog_id":"a30becec-5d62-4211-a937-72611bcac877","title":"插件加载机制","description":"plugin-loading-mechanism","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"447d8f86-c321-4cb4-a42b-efdc97bf8bcb","gmt_create":"2025-12-26T00:50:22+08:00","gmt_modified":"2025-12-26T00:50:22+08:00"},{"catalog_id":"968acb83-28f9-45b5-a177-a7764a39a2f3","title":"调度任务元数据","description":"schedule-job-info","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0cbefc41-fce4-4785-a0cf-f879dbca7135","gmt_create":"2025-12-26T00:50:27+08:00","gmt_modified":"2025-12-26T00:50:27+08:00"},{"catalog_id":"4abfa320-b04c-41ed-aef6-bfdc2fe13c3a","title":"任务调度","description":"task-scheduling","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0c774ddd-d820-4982-84c2-e396ababa803","gmt_create":"2025-12-26T00:50:41+08:00","gmt_modified":"2025-12-26T00:50:41+08:00"},{"catalog_id":"251acb67-6d5e-45eb-b64c-94b11aa2ce30","title":"REST API接口","description":"server-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d6546d25-2b85-4290-adde-19b5018a30e3","gmt_create":"2025-12-26T00:52:02+08:00","gmt_modified":"2025-12-26T00:52:02+08:00"},{"catalog_id":"b4b2446b-5ea0-43e8-973b-48528c40559d","title":"ZooKeeper实现","description":"zookeeper-implementation","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3b586010-118d-457f-b891-4eb2cd2bc9ea","gmt_create":"2025-12-26T00:52:03+08:00","gmt_modified":"2025-12-26T00:52:03+08:00"},{"catalog_id":"724f7889-75f8-4bdd-94c2-bc5fe8255890","title":"引擎API与抽象","description":"engine-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"23c19f37-93ba-429a-b47b-2d2bdc9354dc","gmt_create":"2025-12-26T00:52:05+08:00","gmt_modified":"2025-12-26T00:52:05+08:00"},{"catalog_id":"84f45a10-33fb-4d11-96bc-c2372db645b0","title":"内置度量规则","description":"built-in-metrics","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"603898e3-2004-4267-a3db-25142259b3b2","gmt_create":"2025-12-26T00:54:06+08:00","gmt_modified":"2025-12-26T00:54:06+08:00"},{"catalog_id":"447e40c9-e605-456a-9493-57b6860558ee","title":"JDBC连接器","description":"jdbc-connector","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"7fd23d79-a4be-4774-95d6-d4209e24bf4e","gmt_create":"2025-12-26T00:54:16+08:00","gmt_modified":"2025-12-26T00:54:16+08:00"},{"catalog_id":"e9edaa94-bccc-4cd3-b9cc-e7491ceccf23","title":"ZooKeeper注册中心","description":"zookeeper-registry","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f09cdc5a-cc71-46ef-876a-5425ea0327fe","gmt_create":"2025-12-26T00:55:06+08:00","gmt_modified":"2025-12-26T00:55:06+08:00"},{"catalog_id":"36510586-6119-4b7f-8075-ce313c0bd508","title":"钉钉通知","description":"dingtalk-notification","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"71722d11-c614-4a85-bf0b-7d0c8ea1dad7","gmt_create":"2025-12-26T00:56:04+08:00","gmt_modified":"2025-12-26T00:56:04+08:00"},{"catalog_id":"68f84f86-d6f2-405b-8e9f-31f0bdeec7c3","title":"任务调度API","description":"job-scheduling-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f943043a-d62d-498b-bdc5-f1b0b11c4b4b","gmt_create":"2025-12-26T00:56:24+08:00","gmt_modified":"2025-12-26T00:56:24+08:00"},{"catalog_id":"21179d81-91c3-4822-bf9b-316332af72db","title":"核心页面功能","description":"ui-pages","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e5b5081f-7d21-41e0-944a-5178465da066","gmt_create":"2025-12-26T00:56:55+08:00","gmt_modified":"2025-12-26T00:56:55+08:00"},{"catalog_id":"e52eb8d2-6c53-481b-a2f0-3cdb7d254a92","title":"安全配置","description":"server-security-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"75988d09-2105-4ebf-8f4d-8d84f195685c","gmt_create":"2025-12-26T00:58:06+08:00","gmt_modified":"2025-12-26T00:58:06+08:00"},{"catalog_id":"edf6a573-17c8-4a23-a325-6f396083b131","title":"数据库性能调优","description":"database-performance-tuning","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"5561e196-d14a-49b6-8d5f-b791c54024ea","gmt_create":"2025-12-26T00:58:21+08:00","gmt_modified":"2025-12-26T00:58:21+08:00"},{"catalog_id":"6ce0e176-a6ce-4f78-8d38-8e1aa881f109","title":"任务表 (job)","description":"job-table","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b423af2b-e0e1-41c0-9519-985b5e106926","gmt_create":"2025-12-26T00:58:35+08:00","gmt_modified":"2025-12-26T00:58:35+08:00"},{"catalog_id":"0af499dc-42d0-47d8-a341-f39d5a121c87","title":"邮件配置","description":"email-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"07dc10f4-cb06-4358-b164-7d949e3a0830","gmt_create":"2025-12-26T00:59:59+08:00","gmt_modified":"2025-12-26T00:59:59+08:00"},{"catalog_id":"860d9985-eb7d-432e-a1d2-69e59ae12cef","title":"大数据平台配置","description":"big-data-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"6579034f-efa2-4e84-98a2-7b5dcbbb081e","gmt_create":"2025-12-26T01:00:10+08:00","gmt_modified":"2025-12-26T01:00:10+08:00"},{"catalog_id":"7bd8d8bf-316b-4e5a-a32f-786067c2d1ba","title":"Spark执行配置","description":"spark-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"6a83dfb1-6ad0-4b7b-be74-d2f703e150fe","gmt_create":"2025-12-26T01:01:02+08:00","gmt_modified":"2025-12-26T01:01:02+08:00"},{"catalog_id":"06284609-845c-441c-a8c3-f5d5dd0354e9","title":"授权配置","description":"authorization-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1a27b90c-74db-48fd-81bd-c34bd255ec1a","gmt_create":"2025-12-26T01:01:35+08:00","gmt_modified":"2025-12-26T01:01:35+08:00"},{"catalog_id":"586fb977-73cd-4d21-81a4-ecfb619947f0","title":"变更监控","description":"change-monitoring","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"c646e112-10e4-4618-b290-d1bd1129c913","gmt_create":"2025-12-26T01:02:13+08:00","gmt_modified":"2025-12-26T01:02:13+08:00"},{"catalog_id":"d9c6c09f-4495-4230-aff6-8582fcde95a6","title":"可视化展示","description":"data-profiling-visualization","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"02d70c39-99f2-4361-80c5-e4cb4fcebcf7","gmt_create":"2025-12-26T01:02:32+08:00","gmt_modified":"2025-12-26T01:02:32+08:00"},{"catalog_id":"4fe521c8-eabe-4899-aa88-38fcb7db2d6f","title":"系统启动流程","description":"startup-process","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1dbe65d5-1994-445e-aeed-7ca8a425006c","gmt_create":"2025-12-26T01:03:30+08:00","gmt_modified":"2025-12-26T01:03:30+08:00"},{"catalog_id":"b5926d5f-dbeb-4d9e-a36e-cf98ac31d9de","title":"插件开发指南","description":"plugin-development-guide","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"068e4e4c-7dbd-4cff-865f-e0c41c0081b6","gmt_create":"2025-12-26T01:04:03+08:00","gmt_modified":"2025-12-26T01:04:03+08:00"},{"catalog_id":"89150110-41ce-4344-a684-350172827c8c","title":"结果验证","description":"data-quality-validation","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"40967690-1b17-417e-a87f-705788d6a788","gmt_create":"2025-12-26T01:04:09+08:00","gmt_modified":"2025-12-26T01:04:09+08:00"},{"catalog_id":"20510b1c-4941-42d9-b461-571abbf86340","title":"执行引擎","description":"execution-engine","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f6c98e31-e00f-4acf-b95e-0e98fface5c5","gmt_create":"2025-12-26T01:05:09+08:00","gmt_modified":"2025-12-26T01:05:09+08:00"},{"catalog_id":"14c3b8e9-25f1-4a3d-a52b-32127251a90e","title":"作业执行调度器","description":"job-execution-scheduler","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"168033b1-8344-4ffe-b29c-e2d4c352b2dd","gmt_create":"2025-12-26T01:05:53+08:00","gmt_modified":"2025-12-26T01:05:53+08:00"},{"catalog_id":"c1af4cbc-1bf5-4b48-bdd7-f6be8c87b776","title":"MySQL实现","description":"mysql-implementation","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3d89bb68-2ebe-4851-bbbf-1b81cfc75c11","gmt_create":"2025-12-26T01:06:18+08:00","gmt_modified":"2025-12-26T01:06:18+08:00"},{"catalog_id":"f053dc58-ea0f-45d1-ad5a-3a062ec4df4d","title":"作业配置构建","description":"engine-config","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3f71db44-01be-4380-975c-b6ccd8906956","gmt_create":"2025-12-26T01:07:42+08:00","gmt_modified":"2025-12-26T01:07:42+08:00"},{"catalog_id":"ae9c4797-fad2-4104-bb0e-09c584c89e78","title":"服务层实现","description":"server-service","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b25549e7-1a1b-4262-b87b-68f496c361e5","gmt_create":"2025-12-26T01:07:53+08:00","gmt_modified":"2025-12-26T01:07:53+08:00"},{"catalog_id":"05ecbf2d-dccc-446f-89d3-e1c48ba2e20a","title":"MySQL连接器","description":"mysql-connector","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"89883bfd-09a9-498a-a47e-a3663ffa0fac","gmt_create":"2025-12-26T01:08:22+08:00","gmt_modified":"2025-12-26T01:08:22+08:00"},{"catalog_id":"98e83c1d-0132-4fc2-97bf-3a05405fba4d","title":"邮件通知","description":"email-notification","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"42e75f23-f50f-489e-b726-ce21c69c374b","gmt_create":"2025-12-26T01:09:37+08:00","gmt_modified":"2025-12-26T01:09:37+08:00"},{"catalog_id":"a42f354b-55a2-4356-a7b4-d94e20a79fea","title":"预期值计算系统","description":"expected-value-system","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"86d3b799-a356-479d-9b12-06a16f032b4b","gmt_create":"2025-12-26T01:09:39+08:00","gmt_modified":"2025-12-26T01:09:39+08:00"},{"catalog_id":"24fbd35c-442c-4c05-bab5-c449e4e14720","title":"MySQL注册中心","description":"mysql-registry","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"94c58a7b-b072-4f9b-acbe-6e80f1cf7647","gmt_create":"2025-12-26T01:10:15+08:00","gmt_modified":"2025-12-26T01:10:15+08:00"},{"catalog_id":"ac71af63-8b30-47c9-a170-1572ee4b31d8","title":"任务执行API","description":"job-execution-api","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"40d5dba2-1cb5-4718-abb1-98493fe56ed1","gmt_create":"2025-12-26T01:10:50+08:00","gmt_modified":"2025-12-26T01:10:50+08:00"},{"catalog_id":"29fa1aa5-5021-44cf-b284-95390545e925","title":"UI组件系统","description":"ui-components","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d7b91880-5db8-4f6e-a907-09a610ada8e6","gmt_create":"2025-12-26T01:10:59+08:00","gmt_modified":"2025-12-26T01:10:59+08:00"},{"catalog_id":"3810450a-d4ff-4879-8549-08ed1954e893","title":"日志配置","description":"server-logging-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"10d8c2d5-b907-449d-90c7-b8136ef223c0","gmt_create":"2025-12-26T01:12:20+08:00","gmt_modified":"2025-12-26T01:12:20+08:00"},{"catalog_id":"a58aff9a-6399-4a0a-b4e7-b2b41a7deea0","title":"任务执行表 (job_execution)","description":"job-execution-table","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d9025f64-370a-414f-bf81-59ef536fdc14","gmt_create":"2025-12-26T01:12:29+08:00","gmt_modified":"2025-12-26T01:12:29+08:00"},{"catalog_id":"08bccd0c-f9f2-42df-bd89-4c3cac27a61e","title":"数据库管理","description":"database-management","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f111c3f5-8bb1-4907-9385-bdb81402e1a4","gmt_create":"2025-12-26T01:12:51+08:00","gmt_modified":"2025-12-26T01:12:51+08:00"},{"catalog_id":"3280b206-4eac-4c5b-bc1e-0d8b19a3aeb6","title":"飞书配置","description":"lark-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1e76d9e8-b767-484b-9f9a-27b4b3233e33","gmt_create":"2025-12-26T01:13:47+08:00","gmt_modified":"2025-12-26T01:13:47+08:00"},{"catalog_id":"1e6b21d3-ffbf-4413-b2b1-7835661a6c7a","title":"文件系统配置","description":"file-system-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"636325dc-bc8a-4bd6-9147-5ea10dfbdb58","gmt_create":"2025-12-26T01:14:08+08:00","gmt_modified":"2025-12-26T01:14:08+08:00"},{"catalog_id":"6131ffa8-42da-4114-b25f-2b0255704d52","title":"Flink执行配置","description":"flink-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"430b697e-305e-48c9-8a66-f1e5404d5551","gmt_create":"2025-12-26T01:14:58+08:00","gmt_modified":"2025-12-26T01:14:58+08:00"},{"catalog_id":"6f1fa09a-2cd2-4016-8fe9-896c74cea65f","title":"数据安全配置","description":"data-security-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"019082b2-299a-4ec3-9b07-6096f355ac31","gmt_create":"2025-12-26T01:15:17+08:00","gmt_modified":"2025-12-26T01:15:17+08:00"},{"catalog_id":"a2152a18-ea14-4a41-80d9-cc7645d5b0c9","title":"调度策略","description":"data-quality-scheduling","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"cb8ab5c0-64d4-4f64-b62d-0f28cd29f12e","gmt_create":"2025-12-26T01:16:01+08:00","gmt_modified":"2025-12-26T01:16:01+08:00"},{"catalog_id":"d6c19b9b-50fa-4271-98d9-b3558ca0cc04","title":"客户端管理","description":"client-management","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"6dedece1-3d65-4251-a3f7-3c6fd05657be","gmt_create":"2025-12-26T01:16:52+08:00","gmt_modified":"2025-12-26T01:16:52+08:00"},{"catalog_id":"749e3852-d9e1-4440-ae18-a69d01ab8dbe","title":"结果验证","description":"result-verification","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d64dafa2-9b28-49c1-b140-df804355c0cb","gmt_create":"2025-12-26T01:17:20+08:00","gmt_modified":"2025-12-26T01:17:20+08:00"},{"catalog_id":"07b63f3a-0384-4d83-9231-bdcd684fc464","title":"执行器实现","description":"engine-executor","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"9d43b1ad-ce04-4422-b736-cc8edf592394","gmt_create":"2025-12-26T01:18:23+08:00","gmt_modified":"2025-12-26T01:18:23+08:00"},{"catalog_id":"bbd65494-8a17-4b10-9e78-b360cb044f38","title":"数据质量协调","description":"server-dqc","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"094cefaf-bbca-448f-a303-c381ff621065","gmt_create":"2025-12-26T01:18:26+08:00","gmt_modified":"2025-12-26T01:18:26+08:00"},{"catalog_id":"b9b25676-6bfa-41d9-9558-05107be3b608","title":"PostgreSQL连接器","description":"postgresql-connector","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"319f1a59-2575-486f-8e89-59f66b353c94","gmt_create":"2025-12-26T01:19:02+08:00","gmt_modified":"2025-12-26T01:19:02+08:00"},{"catalog_id":"43bcf23c-8363-45c6-bda9-4f0d569ad332","title":"飞书通知","description":"lark-notification","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d319ae5e-0fa2-464d-8ec7-0452c636b895","gmt_create":"2025-12-26T01:19:49+08:00","gmt_modified":"2025-12-26T01:19:49+08:00"},{"catalog_id":"b792898c-8eac-4dc1-81fb-6d553602e3c7","title":"API集成与数据流","description":"ui-api-integration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f4f84152-05d4-4383-9d9e-2e1e15e5b5b8","gmt_create":"2025-12-26T01:20:05+08:00","gmt_modified":"2026-02-05T02:04:29.1556156+08:00"},{"catalog_id":"5dd0b02c-33a2-4854-9b60-5447e197432d","title":"结果计算公式","description":"result-formula","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ce75cf08-4a31-4449-8d9d-fa47d16365dd","gmt_create":"2025-12-26T01:20:06+08:00","gmt_modified":"2025-12-26T01:20:06+08:00"},{"catalog_id":"30a874fb-babc-4cea-887d-d8993e5ae436","title":"企业微信配置","description":"wecom-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"52f1e4a2-274c-4bd0-82a4-91140d41a8ad","gmt_create":"2025-12-26T01:21:35+08:00","gmt_modified":"2025-12-26T01:21:35+08:00"},{"catalog_id":"10fb4d0e-6886-43f0-9f3a-7e3c1e6b8221","title":"性能配置","description":"server-performance-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a185d6d3-65d3-42ce-9fed-34d262f82c59","gmt_create":"2025-12-26T01:22:27+08:00","gmt_modified":"2025-12-26T01:22:27+08:00"},{"catalog_id":"176779db-46f6-4869-90b6-039bd05637dd","title":"用户表 (user)","description":"user-table","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"88e03e88-d22c-4ebc-b071-74ecc7f65860","gmt_create":"2025-12-26T01:22:45+08:00","gmt_modified":"2025-12-26T01:22:45+08:00"},{"catalog_id":"e27cf36e-27dd-4b26-a11a-f8f2af97306c","title":"资源调度配置","description":"resource-scheduling-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"5ba8ddd2-8eec-465e-a450-fc22d92bb196","gmt_create":"2025-12-26T01:23:18+08:00","gmt_modified":"2025-12-26T01:23:18+08:00"},{"catalog_id":"72b97911-e2e4-4b09-bde2-f0f2d90d1023","title":"认证与权限","description":"server-security","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"c7c1b23e-9e57-4fe0-b507-b33dbce122c2","gmt_create":"2025-12-26T01:24:08+08:00","gmt_modified":"2025-12-26T01:24:08+08:00"},{"catalog_id":"6097d24c-f261-403b-8385-f5e46e22ec1a","title":"Oracle连接器","description":"oracle-connector","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"2cee7d06-6eea-47ca-bfdf-a4f9f3b7b98d","gmt_create":"2025-12-26T01:24:47+08:00","gmt_modified":"2025-12-26T01:24:47+08:00"},{"catalog_id":"070c1d7f-c3fd-4161-950a-e255d4da1319","title":"企业微信通知","description":"wecombot-notification","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"7f9cbdb3-c4a1-45fe-a027-3ed45c0c98b2","gmt_create":"2025-12-26T01:25:38+08:00","gmt_modified":"2025-12-26T01:25:38+08:00"},{"catalog_id":"aa8efb1b-1c99-4fe2-a451-746364c7e416","title":"执行引擎插件","description":"engine-plugins","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"37db4c74-0075-4d61-a617-961a2bb2b02c","gmt_create":"2025-12-26T01:25:38+08:00","gmt_modified":"2025-12-26T01:25:38+08:00"},{"catalog_id":"ee36f1eb-9d0a-46b0-b7b4-ebcfba792d43","title":"开发与部署指南","description":"ui-development-guide","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"471312d7-c6bd-44db-8135-b041a3307f3f","gmt_create":"2025-12-26T01:25:52+08:00","gmt_modified":"2025-12-26T01:25:52+08:00"},{"catalog_id":"d5f7d43c-5749-47b2-b0d2-19af59147dd9","title":"任务调度系统","description":"server-scheduler","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e6b9d590-5e80-4e8a-99e5-5cbbed8e6c33","gmt_create":"2025-12-26T01:28:01+08:00","gmt_modified":"2025-12-26T01:28:01+08:00"},{"catalog_id":"25eaa31d-ebf0-4074-88af-1517e7799494","title":"SLA告警配置","description":"sla-notification-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"cc8642e5-2540-46af-857a-5ec76a8aae5f","gmt_create":"2025-12-26T01:28:10+08:00","gmt_modified":"2025-12-26T01:28:10+08:00"},{"catalog_id":"2cc32935-3372-4d39-966f-a179c9b39236","title":"实体定义","description":"entity-definition","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"7790558f-0a96-4611-98ed-ce93b8062382","gmt_create":"2025-12-26T01:29:37+08:00","gmt_modified":"2025-12-26T01:29:37+08:00"},{"catalog_id":"53232b0a-1eea-4a65-91b9-97803ab5210f","title":"工作空间表 (workspace)","description":"workspace-table","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"766e4185-f81b-4a3e-b123-51fc4227719f","gmt_create":"2025-12-26T01:30:25+08:00","gmt_modified":"2025-12-26T01:30:25+08:00"},{"catalog_id":"53211d84-e495-43aa-be3c-b264852c4be1","title":"Hive连接器","description":"hive-connector","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"eadca672-1598-41ce-a817-87a2c5820792","gmt_create":"2025-12-26T01:30:26+08:00","gmt_modified":"2025-12-26T01:30:26+08:00"},{"catalog_id":"3d773a1a-5048-4229-8e0c-730b504662ff","title":"变更检测","description":"change-detection","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"eb17d43f-dd63-4a30-8829-a28cb4d7abd5","gmt_create":"2025-12-26T01:30:56+08:00","gmt_modified":"2025-12-26T01:30:56+08:00"},{"catalog_id":"a4229e60-a19f-49bc-a5f2-fef9a3cc6e34","title":"图表类型","description":"chart-types","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"c9d64d07-51fb-4f95-9065-6f3fbb43707d","gmt_create":"2025-12-26T01:31:38+08:00","gmt_modified":"2025-12-26T01:31:38+08:00"},{"catalog_id":"6a79461b-e8a0-4873-a4f8-eb99eedcc7ed","title":"配置方式","description":"data-profiling-configuration-methods","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0a4a3e22-f70e-4c53-8919-cb185f2db113","gmt_create":"2025-12-26T01:31:51+08:00","gmt_modified":"2025-12-26T01:31:51+08:00"},{"catalog_id":"bb7eb5cf-d368-4e47-ba97-fcc83e5f3de3","title":"Server组件","description":"server-component","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"fd91b637-1310-48e1-940f-29f3fe60832e","gmt_create":"2025-12-26T01:32:15+08:00","gmt_modified":"2025-12-26T01:32:15+08:00"},{"catalog_id":"389c117e-1ada-4683-80ae-fb508cb84925","title":"Spring上下文初始化","description":"spring-context-initialization","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"fb7f51a9-b4f2-4928-b61b-7cdc4ef13713","gmt_create":"2025-12-26T01:33:22+08:00","gmt_modified":"2025-12-26T01:33:22+08:00"},{"catalog_id":"bfcfc439-ddb2-439a-b44b-cc168804d1c9","title":"任务调度机制","description":"task-scheduling","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0651839c-1a4f-4a06-968e-991ddd90e5a8","gmt_create":"2025-12-26T01:33:38+08:00","gmt_modified":"2025-12-26T01:33:38+08:00"},{"catalog_id":"0119e5f6-79b0-4d58-813a-14a0a719454e","title":"单表检查","description":"single-table-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"2a4279e9-8563-47d9-9f71-91a4b9964c57","gmt_create":"2025-12-26T01:34:27+08:00","gmt_modified":"2025-12-26T01:34:27+08:00"},{"catalog_id":"54f9b430-fe21-493c-8d14-bafe2c3002be","title":"执行平台","description":"execution-platforms","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"6df78b08-2493-44df-a726-1492b2208603","gmt_create":"2025-12-26T01:34:45+08:00","gmt_modified":"2025-12-26T01:34:45+08:00"},{"catalog_id":"007c1da6-4f63-4934-96f3-2a1b1b854abf","title":"验证流程","description":"validation-process","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0e61102d-3011-4753-beb8-4c9e0e04149e","gmt_create":"2025-12-26T01:35:16+08:00","gmt_modified":"2025-12-26T01:35:16+08:00"},{"catalog_id":"149d22d4-1dbc-436e-a0ba-27e764925bde","title":"调度类型","description":"scheduling-types","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ec95145e-40cb-421b-8cd8-a3a6101a7f17","gmt_create":"2025-12-26T01:36:34+08:00","gmt_modified":"2025-12-26T01:36:34+08:00"},{"catalog_id":"e89b1596-ff9d-4c3d-9c16-0200b89a07f6","title":"本地执行","description":"local-execution","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"481369da-d759-445b-a0dd-cdc62566a219","gmt_create":"2025-12-26T01:36:53+08:00","gmt_modified":"2025-12-26T01:36:53+08:00"},{"catalog_id":"cb86625d-920e-447f-a3e2-27f8369c611e","title":"调度管理","description":"scheduling-management","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"793d818e-c21e-4bf7-b8b2-159832759e8e","gmt_create":"2025-12-26T01:36:53+08:00","gmt_modified":"2025-12-26T01:36:53+08:00"},{"catalog_id":"b4f46806-f78c-4b12-af87-a7a7fa341206","title":"任务管理API","description":"api-job","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"6788ea2d-7323-4b4e-a9b3-e06ea8743154","gmt_create":"2025-12-26T01:38:16+08:00","gmt_modified":"2025-12-26T01:38:16+08:00"},{"catalog_id":"a493ad0e-2c21-46e7-bee0-76a79ce38c1a","title":"EngineExecutor接口","description":"engine-executor","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"6be8466c-f161-4330-bb7e-d2645011f1e4","gmt_create":"2025-12-26T01:38:26+08:00","gmt_modified":"2025-12-26T01:38:26+08:00"},{"catalog_id":"29e01068-144e-4924-bf78-a196f6575029","title":"调度管理","description":"dqc-scheduler","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"8e26ea4f-1779-4832-a60b-0bfb57b9d601","gmt_create":"2025-12-26T01:38:35+08:00","gmt_modified":"2025-12-26T01:38:35+08:00"},{"catalog_id":"7f956d92-98d5-4434-8c9b-749ee8faadfc","title":"抽象执行器基类","description":"abstract-engine-executor","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f6f57334-59ea-417f-8a4d-d8e9ec52b6b5","gmt_create":"2025-12-26T01:39:59+08:00","gmt_modified":"2025-12-26T01:39:59+08:00"},{"catalog_id":"8195f94f-7c42-40f0-8e98-ab1163cac8ae","title":"单表检查规则","description":"single-table-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"c8f9b14f-32c0-4117-bac6-dd345760e2e6","gmt_create":"2025-12-26T01:40:43+08:00","gmt_modified":"2025-12-26T01:40:43+08:00"},{"catalog_id":"8b327b52-c92a-4f28-933e-dbc7ff98d357","title":"Flink执行引擎","description":"flink-engine","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b19cb4d2-e3f3-4904-b675-97b0e9a7209b","gmt_create":"2025-12-26T01:42:08+08:00","gmt_modified":"2025-12-26T01:42:08+08:00"},{"catalog_id":"674fea1e-97be-4cb1-bd76-900dc70b7b59","title":"固定值策略","description":"fixed-value-strategy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"102274b5-f1dc-438c-8d7e-1eaf7b6a9a71","gmt_create":"2025-12-26T01:42:10+08:00","gmt_modified":"2025-12-26T01:42:10+08:00"},{"catalog_id":"44ca2346-0af3-4baa-80ce-b4d555126b9e","title":"开发环境搭建","description":"ui-development-setup","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1c16cc97-b397-4075-8585-3a7013372fde","gmt_create":"2025-12-26T01:43:05+08:00","gmt_modified":"2025-12-26T01:43:05+08:00"},{"catalog_id":"00ec5d54-4aef-4a88-ae30-224227f025c0","title":"首页功能","description":"ui-home","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ad4bee1f-9a9c-492e-a98c-8abb58a8fdc3","gmt_create":"2025-12-26T01:43:41+08:00","gmt_modified":"2025-12-26T01:43:41+08:00"},{"catalog_id":"b198fd72-b1de-49ea-896c-25e9c1c87ca9","title":"通用组件","description":"common-components","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"581d9a67-73b8-47f4-9c52-8d78f3834a23","gmt_create":"2025-12-26T01:44:20+08:00","gmt_modified":"2025-12-26T01:44:20+08:00"},{"catalog_id":"b2a836fd-0bf7-453e-b77b-1e65b0b5e6d2","title":"作业服务实现","description":"job-service","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"c4d8e391-a6a6-420f-9087-0ac2b54b08ad","gmt_create":"2025-12-26T01:44:25+08:00","gmt_modified":"2025-12-26T01:44:25+08:00"},{"catalog_id":"1f6711c9-86b6-4a23-9777-f70d30f330b9","title":"YARN资源配置","description":"yarn-resource-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3f6d1151-9229-4546-89f7-2db2952b68e8","gmt_create":"2025-12-26T01:45:42+08:00","gmt_modified":"2025-12-26T01:45:42+08:00"},{"catalog_id":"bfba18be-d14a-45ce-94d5-f1f20d8eb9f4","title":"Hive配置","description":"hive-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e35fe7d5-15ea-4211-a3f1-4f879de4710f","gmt_create":"2025-12-26T01:46:02+08:00","gmt_modified":"2025-12-26T01:46:02+08:00"},{"catalog_id":"08b83736-30ba-4a22-8df4-995f1b7fa67d","title":"Spark直接执行配置","description":"spark-direct-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"af3014f6-c4f6-4bfe-aec4-156c35edc01b","gmt_create":"2025-12-26T01:46:33+08:00","gmt_modified":"2025-12-26T01:46:33+08:00"},{"catalog_id":"14e43aee-442f-4529-8b9e-70ae58302321","title":"本地文件系统配置","description":"local-file-system-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"54347446-3f36-4bde-a3aa-fcc8886848d1","gmt_create":"2025-12-26T01:47:00+08:00","gmt_modified":"2025-12-26T01:47:00+08:00"},{"catalog_id":"a75a8336-b210-4129-aa77-27fd38e575c1","title":"Token管理","description":"token-management","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"875a096f-6990-48c8-9a58-6b25b53ba3b9","gmt_create":"2025-12-26T01:47:42+08:00","gmt_modified":"2025-12-26T01:47:42+08:00"},{"catalog_id":"da32bc6b-65b5-41ad-aca8-56209ab4b5ab","title":"MySQL配置","description":"mysql-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"51dfa669-f053-418e-bfa0-39ea7f5af63f","gmt_create":"2025-12-26T01:48:08+08:00","gmt_modified":"2025-12-26T01:48:08+08:00"},{"catalog_id":"d0eec0e2-c60f-4a03-85d4-67f42710e1eb","title":"访问控制","description":"access-control","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3a78dcf6-2a26-4fd8-bb8b-e43174a78bb6","gmt_create":"2025-12-26T01:48:32+08:00","gmt_modified":"2025-12-26T01:48:32+08:00"},{"catalog_id":"24247a11-9e9d-4d52-8825-9a647827b4d0","title":"实体实例","description":"entity-instance","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"bd2f798b-6fe9-478a-9ec4-610204aeeeff","gmt_create":"2025-12-26T01:49:57+08:00","gmt_modified":"2025-12-26T01:49:57+08:00"},{"catalog_id":"c289c71d-0511-435b-9d74-e95ccb25ce36","title":"加密管理","description":"encryption-management","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"6feb76e1-5555-4ef1-8095-6bb7f19945fe","gmt_create":"2025-12-26T01:49:57+08:00","gmt_modified":"2025-12-26T01:49:57+08:00"},{"catalog_id":"802ef802-00bf-4a33-b9f3-157d415741e7","title":"变更通知","description":"change-notification","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f14282f3-81ce-4910-aa45-06345ac7fded","gmt_create":"2025-12-26T01:50:33+08:00","gmt_modified":"2025-12-26T01:50:33+08:00"},{"catalog_id":"f3e24d9b-800b-4069-8a55-9e29462eb1f9","title":"交互操作","description":"interactive-operations","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b5d8c2de-e4dd-41c3-b6fb-ccfed9cc6007","gmt_create":"2025-12-26T01:51:31+08:00","gmt_modified":"2025-12-26T01:51:31+08:00"},{"catalog_id":"27b6b757-6ebd-406f-ad0d-967146ad8915","title":"参数说明","description":"data-profiling-configuration-parameters","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"46434d6d-23dc-475f-bfb7-1c3f8fe62325","gmt_create":"2025-12-26T01:51:34+08:00","gmt_modified":"2025-12-26T01:51:34+08:00"},{"catalog_id":"6f1a9144-3aff-43c9-84ad-aba96b1a50bb","title":"Engine组件","description":"engine-component","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"712c5e76-a1ab-47f7-9f60-b729f1164697","gmt_create":"2025-12-26T01:52:12+08:00","gmt_modified":"2025-12-26T01:52:12+08:00"},{"catalog_id":"8686fc3b-bec7-4b41-ae35-31b1eaca7987","title":"数据通信协议","description":"data-communication","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"18ad9731-a15d-4bf0-9c19-de571e4b9a87","gmt_create":"2025-12-26T01:52:53+08:00","gmt_modified":"2025-12-26T01:52:53+08:00"},{"catalog_id":"8ccd960d-5ab7-4c37-baa2-3ec94067dcd8","title":"服务注册与发现","description":"service-registration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"44bd8148-c8e0-4623-bfcb-32396ac0bd3e","gmt_create":"2025-12-26T01:53:44+08:00","gmt_modified":"2025-12-26T01:53:44+08:00"},{"catalog_id":"8a7821e9-9176-4c43-ae8a-64769c6958b2","title":"跨表检查","description":"cross-table-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"20d50b39-4ee6-4447-a8ea-9315d64aa6c6","gmt_create":"2025-12-26T01:54:08+08:00","gmt_modified":"2025-12-26T01:54:08+08:00"},{"catalog_id":"5a5f7336-b3d2-4a29-bc1f-277b3fb38204","title":"资源配置","description":"resource-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ed559bfd-0527-413e-a783-7ffdda3cd03b","gmt_create":"2025-12-26T01:54:15+08:00","gmt_modified":"2025-12-26T01:54:15+08:00"},{"catalog_id":"0ecae61e-c4cc-4be3-8858-dd5fe32600a6","title":"预期值计算","description":"expected-value-calculation","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"deafb08f-06f7-48f1-995d-0d652248a7e4","gmt_create":"2025-12-26T01:55:31+08:00","gmt_modified":"2025-12-26T01:55:31+08:00"},{"catalog_id":"d0247d4f-b68d-4c7d-9ab7-65a926f5b82a","title":"执行逻辑","description":"execution-logic","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f0c1d3fa-3481-49e1-8d20-13e85e72d715","gmt_create":"2025-12-26T01:55:41+08:00","gmt_modified":"2025-12-26T01:55:41+08:00"},{"catalog_id":"2afec718-6318-40a5-a6d3-484810b76536","title":"生命周期管理","description":"lifecycle-management","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e7e907eb-8f12-42a9-bde8-70388f0a36ef","gmt_create":"2025-12-26T01:56:01+08:00","gmt_modified":"2025-12-26T01:56:01+08:00"},{"catalog_id":"ff00b230-16ce-4cae-ab84-1edefb13079a","title":"任务参数构建","description":"dqc-parameter-builder","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e0c7c0e3-087c-4853-8225-8027a1fc9d72","gmt_create":"2025-12-26T01:56:56+08:00","gmt_modified":"2025-12-26T01:56:56+08:00"},{"catalog_id":"0f2a22f3-1d66-49d4-af7e-b67e98911858","title":"数据源管理API","description":"api-datasource","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0e759f36-f414-4f34-960b-0869878d3e7d","gmt_create":"2025-12-26T01:57:35+08:00","gmt_modified":"2025-12-26T01:57:35+08:00"},{"catalog_id":"ac49273b-a216-4c15-845b-99e5397bb798","title":"Yarn执行","description":"yarn-execution","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b425b514-387b-4ed6-8633-7f420d21cc75","gmt_create":"2025-12-26T01:57:36+08:00","gmt_modified":"2025-12-26T01:57:36+08:00"},{"catalog_id":"75b89676-2378-454e-9029-3ee7ce30ac24","title":"RuntimeEnvironment接口","description":"runtime-environment","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a342ceec-0617-428c-8b63-bb3cbf14e5b9","gmt_create":"2025-12-26T01:58:17+08:00","gmt_modified":"2025-12-26T01:58:17+08:00"},{"catalog_id":"b6915c42-1b23-47b4-8a82-8d77f4d06fe7","title":"数据源服务实现","description":"data-source-service","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0b08475f-5111-4786-9af6-fd1200d8be57","gmt_create":"2025-12-26T01:59:40+08:00","gmt_modified":"2025-12-26T01:59:40+08:00"},{"catalog_id":"03c2fc14-d1f4-4beb-a517-abf842d366e4","title":"跨表检查规则","description":"cross-table-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1d63951f-cd45-44e3-87a2-92409b9a7e2d","gmt_create":"2025-12-26T01:59:56+08:00","gmt_modified":"2025-12-26T01:59:56+08:00"},{"catalog_id":"490f16ea-d490-4acf-bd66-84b831b25bed","title":"Livy执行器","description":"livy-executor","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"5cc19fcb-de0c-4981-92e7-2ef78d574568","gmt_create":"2025-12-26T01:59:57+08:00","gmt_modified":"2025-12-26T01:59:57+08:00"},{"catalog_id":"4877b289-0dff-4019-923a-91501c54a7a5","title":"Spark执行引擎","description":"spark-engine","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"31c68c10-2c5b-404d-911f-303fdecea54c","gmt_create":"2025-12-26T02:01:17+08:00","gmt_modified":"2025-12-26T02:01:17+08:00"},{"catalog_id":"489baeb5-14c4-4d03-b73b-be142d956487","title":"时间序列平均值策略","description":"time-series-avg-strategy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"21a428e9-0608-4e68-9179-f7aac4fdfdb1","gmt_create":"2025-12-26T02:01:52+08:00","gmt_modified":"2025-12-26T02:01:52+08:00"},{"catalog_id":"e6987f90-3aa6-4080-9d4c-676c44cf7263","title":"任务管理","description":"ui-jobs","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"80a06058-0f75-4b52-9eaa-b8b20764d612","gmt_create":"2025-12-26T02:01:58+08:00","gmt_modified":"2025-12-26T02:01:58+08:00"},{"catalog_id":"b42b93a7-226c-411e-8a13-c7827801d7c6","title":"生产环境部署","description":"ui-production-deployment","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"9b6ce2f1-7c07-4f5a-a41b-ad09bb2b4748","gmt_create":"2025-12-26T02:02:18+08:00","gmt_modified":"2025-12-26T02:02:18+08:00"},{"catalog_id":"25c1fc51-6b17-41eb-8829-6f749d16d128","title":"布局组件","description":"layout-components","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1889387a-f153-4e20-821c-e2ae3682b26d","gmt_create":"2025-12-26T02:03:08+08:00","gmt_modified":"2025-12-26T02:03:08+08:00"},{"catalog_id":"33d4bb84-a5bd-4eba-bbea-aa4e5de209f0","title":"Livy资源配置","description":"livy-resource-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"02061ae3-3edf-4281-a095-d9f6ed89d3f4","gmt_create":"2025-12-26T02:03:31+08:00","gmt_modified":"2025-12-26T02:03:31+08:00"},{"catalog_id":"b6920582-174f-424f-a6fc-f9e172a29ac9","title":"Spark Livy配置","description":"spark-livy-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"66b85aaa-b47b-4bde-ab17-2ff45298b2fa","gmt_create":"2025-12-26T02:04:05+08:00","gmt_modified":"2025-12-26T02:04:05+08:00"},{"catalog_id":"d29ef881-2a58-4b10-b394-0120517f7d7b","title":"Spark配置","description":"spark-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a4d07efc-2328-493e-9c85-ad96981b4a0d","gmt_create":"2025-12-26T02:04:44+08:00","gmt_modified":"2025-12-26T02:04:44+08:00"},{"catalog_id":"e85fa451-84c1-4218-9ff7-9d263c03553b","title":"分布式文件系统配置","description":"distributed-file-system-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a0ecf4d2-f988-42d3-a5c1-212e99527d70","gmt_create":"2025-12-26T02:05:34+08:00","gmt_modified":"2025-12-26T02:05:34+08:00"},{"catalog_id":"0bda8e18-09ed-418f-899c-e094cdb2fee2","title":"验证码配置","description":"captcha-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0197ae18-c53e-4097-a1dc-f838fa44dd28","gmt_create":"2025-12-26T02:06:20+08:00","gmt_modified":"2025-12-26T02:06:20+08:00"},{"catalog_id":"8f331b81-615f-484a-9128-da0c76a96189","title":"PostgreSQL配置","description":"postgresql-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"70b79193-4792-4c10-a728-7807045e44ad","gmt_create":"2025-12-26T02:06:31+08:00","gmt_modified":"2025-12-26T02:06:31+08:00"},{"catalog_id":"71ac64cb-e9b4-449e-a217-d00b31969fc9","title":"权限模型","description":"permission-model","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3819148c-146f-4169-a3f4-9cf70e3845f4","gmt_create":"2025-12-26T02:07:00+08:00","gmt_modified":"2025-12-26T02:07:00+08:00"},{"catalog_id":"f4818220-af24-457c-b8d1-d03fc03f455c","title":"日志安全","description":"log-security","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3a24ed08-8ca5-44a6-b931-2685db1fbc2f","gmt_create":"2025-12-26T02:07:27+08:00","gmt_modified":"2025-12-26T02:07:27+08:00"},{"catalog_id":"7bd2f784-7e4f-47a3-858c-5949004f1d3c","title":"元数据查询","description":"metadata-query","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"52d30486-a94a-47bc-a557-2cdd00db5138","gmt_create":"2025-12-26T02:07:59+08:00","gmt_modified":"2025-12-26T02:07:59+08:00"},{"catalog_id":"b5950a58-eaa5-4a3a-abe1-aafda3088310","title":"分析场景","description":"analysis-scenarios","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a0d9a357-32d1-44a4-a4b0-d340c18a4dff","gmt_create":"2025-12-26T02:08:42+08:00","gmt_modified":"2025-12-26T02:08:42+08:00"},{"catalog_id":"791a766b-a5c3-4467-b7b9-b5e08e90ab3a","title":"影响分析","description":"impact-analysis","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e735406b-56b3-4ed3-9872-850ca3f1d817","gmt_create":"2025-12-26T02:09:09+08:00","gmt_modified":"2025-12-26T02:09:09+08:00"},{"catalog_id":"3614ee98-0803-4f0e-9a53-acbdb7f2438d","title":"执行引擎配置","description":"data-profiling-engine-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"cad35cc6-2548-4bf8-ba3b-a861062c4332","gmt_create":"2025-12-26T02:09:34+08:00","gmt_modified":"2025-12-26T02:09:34+08:00"},{"catalog_id":"b282f234-c03a-42ab-a5ba-d212befebae0","title":"状态同步机制","description":"state-synchronization","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"38bea12a-9467-4d2a-8ff6-0d1f4246b221","gmt_create":"2025-12-26T02:10:41+08:00","gmt_modified":"2025-12-26T02:10:41+08:00"},{"catalog_id":"e3ca53ad-7c0f-45b2-b03a-0e9392040c5a","title":"定时任务调度器初始化","description":"quartz-scheduler-initialization","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e4574700-da89-4b6c-9cfc-8b4bd1b8a4ff","gmt_create":"2025-12-26T02:10:48+08:00","gmt_modified":"2025-12-26T02:10:48+08:00"},{"catalog_id":"7fb0680a-a75a-4a34-bb64-b3eef58c4117","title":"Connector组件","description":"connector-component","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d297d929-a145-4707-82cb-323255f0ef05","gmt_create":"2025-12-26T02:10:51+08:00","gmt_modified":"2025-12-26T02:10:51+08:00"},{"catalog_id":"1ae6ea37-725e-453d-8aa5-a996f78c44e5","title":"结果公式","description":"result-formula","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0030f9ac-7de3-4709-a351-17470a4597ea","gmt_create":"2025-12-26T02:12:22+08:00","gmt_modified":"2025-12-26T02:12:22+08:00"},{"catalog_id":"0f41c3d4-b367-4182-a74f-68659a334ed2","title":"调度策略","description":"scheduling-strategy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3ac19ad0-1d5e-4f68-86b4-c1ff5febef19","gmt_create":"2025-12-26T02:12:22+08:00","gmt_modified":"2025-12-26T02:12:22+08:00"},{"catalog_id":"ddcf75a3-a063-4182-965d-304375d80bb8","title":"自定义SQL检查","description":"custom-sql-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"5fe7502f-3236-49bd-9b64-4ce0f5c991ce","gmt_create":"2025-12-26T02:12:30+08:00","gmt_modified":"2025-12-26T02:12:30+08:00"},{"catalog_id":"2c2434ea-3e77-4ad8-9d00-08caa2b60d52","title":"Livy执行","description":"livy-execution","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"22cb0edf-145a-4ac1-b530-0f2d35aebd7d","gmt_create":"2025-12-26T02:14:13+08:00","gmt_modified":"2025-12-26T02:14:13+08:00"},{"catalog_id":"ea75e4bc-2262-4da2-8967-d58c8586631e","title":"命令模式实现","description":"dqc-command-pattern","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"daeacd00-9e9a-4b04-8ebc-a1ee328c14ff","gmt_create":"2025-12-26T02:14:19+08:00","gmt_modified":"2025-12-26T02:14:19+08:00"},{"catalog_id":"699470e7-5059-4e5b-a919-5b51219326c7","title":"性能优化","description":"performance-optimization","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"a9030c1a-fc6b-4992-a431-ad3ad69e2a4f","gmt_create":"2025-12-26T02:14:27+08:00","gmt_modified":"2025-12-26T02:14:27+08:00"},{"catalog_id":"cbe5c43b-3d93-4d0c-84d5-4a6926379c87","title":"认证与用户管理API","description":"api-auth","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"bade36a8-290c-4347-91ab-7b546f4b3aac","gmt_create":"2025-12-26T02:15:27+08:00","gmt_modified":"2025-12-26T02:15:27+08:00"},{"catalog_id":"52a2b439-0a26-4b28-b7f6-a29cfdb075f9","title":"Component接口","description":"component","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"465aef1b-efcc-43ac-bd36-9c0373de8001","gmt_create":"2025-12-26T02:15:53+08:00","gmt_modified":"2025-12-26T02:15:53+08:00"},{"catalog_id":"c9c4ec65-71ac-4795-bd4d-1829346b6863","title":"调度服务实现","description":"schedule-service","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"885458a5-fd69-46c4-abc1-e6851df34890","gmt_create":"2025-12-26T02:17:06+08:00","gmt_modified":"2025-12-26T02:17:06+08:00"},{"catalog_id":"45955f2d-4b10-4c9e-b1fe-9fa717cafbb9","title":"自定义SQL检查规则","description":"custom-sql-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1d436f91-b0c2-4bf7-9fe5-e0efb1de13a7","gmt_create":"2025-12-26T02:17:25+08:00","gmt_modified":"2025-12-26T02:17:25+08:00"},{"catalog_id":"5ea4662b-d21f-4335-a5bd-4cfd79cc030d","title":"Yarn执行器","description":"yarn-executor","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"27673d4c-18f7-4b6d-9b9f-0fd17623bfd6","gmt_create":"2025-12-26T02:17:29+08:00","gmt_modified":"2025-12-26T02:17:29+08:00"},{"catalog_id":"2053fee1-5d79-47ee-9bb3-cb3407865e4b","title":"本地执行引擎","description":"local-engine","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"7d90e46e-f65b-4686-9b3c-52670f5c864b","gmt_create":"2025-12-26T02:18:36+08:00","gmt_modified":"2025-12-26T02:18:36+08:00"},{"catalog_id":"716ce20b-26af-424a-a4bc-414abaeab0d3","title":"告警管理","description":"ui-warning","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0acd135f-5f00-4bdb-bc34-956d870d51a7","gmt_create":"2025-12-26T02:18:59+08:00","gmt_modified":"2025-12-26T02:18:59+08:00"},{"catalog_id":"c33cdde3-8370-4e56-8838-18df48b76d0d","title":"特殊策略","description":"special-strategy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"93b573e9-4eef-41c1-8627-e67e39372284","gmt_create":"2025-12-26T02:19:15+08:00","gmt_modified":"2025-12-26T02:19:15+08:00"},{"catalog_id":"03dbe7cf-db8c-47a5-aed3-279915fd035f","title":"工具类组件","description":"utility-components","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"701392b9-78b8-48db-972e-c67a61311890","gmt_create":"2025-12-26T02:19:49+08:00","gmt_modified":"2025-12-26T02:19:49+08:00"},{"catalog_id":"82a76e9b-d01b-428c-8fe9-4a08f4cf850c","title":"Flink配置","description":"flink-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d25ed95b-8158-40cd-bea0-36c1c7e258f9","gmt_create":"2025-12-26T02:20:32+08:00","gmt_modified":"2025-12-26T02:20:32+08:00"},{"catalog_id":"34d65e98-52ed-4aa1-83e1-de9389ed10c4","title":"云存储配置","description":"cloud-storage-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"9a63a608-6170-4c1a-aa98-8478a14c9359","gmt_create":"2025-12-26T02:21:21+08:00","gmt_modified":"2025-12-26T02:21:21+08:00"},{"catalog_id":"11049f94-bae2-4321-87ea-f59868608802","title":"Oracle配置","description":"oracle-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"116d0eed-54bb-41f9-b5c0-63779ad2bc55","gmt_create":"2025-12-26T02:21:36+08:00","gmt_modified":"2025-12-26T02:21:36+08:00"},{"catalog_id":"13116af1-c143-42c1-9e22-8310128cf4b0","title":"元数据同步","description":"metadata-sync","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b2a8d5c8-fa1b-4f1e-a177-e9bbdc52fdce","gmt_create":"2025-12-26T02:21:55+08:00","gmt_modified":"2025-12-26T02:21:55+08:00"},{"catalog_id":"30baef90-499c-4bee-8229-830bfa4edb83","title":"审批流程","description":"approval-process","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"180d0cbd-a5ca-493d-9e16-ad074de422f7","gmt_create":"2025-12-26T02:22:37+08:00","gmt_modified":"2025-12-26T02:22:37+08:00"},{"catalog_id":"d8bcc029-a1d3-4a7d-9c6b-37e0e94241ee","title":"SLA与告警管理API","description":"api-sla","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"9532ad15-80ea-483b-a8a5-011bf0756a28","gmt_create":"2025-12-26T02:23:11+08:00","gmt_modified":"2025-12-26T02:23:11+08:00"},{"catalog_id":"0d218996-d4db-4607-b1b2-2300e988f3a0","title":"容错与日志","description":"dqc-failover","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e93422fe-1e08-47d3-a26a-220bfd2dc740","gmt_create":"2025-12-26T02:23:25+08:00","gmt_modified":"2025-12-26T02:23:25+08:00"},{"catalog_id":"c01d3592-d2c8-46ef-972d-f776a6b5d2be","title":"EngineConstants常量类","description":"engine-constants","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"bef7ab2e-17f3-4122-8f3c-61c3bc3088eb","gmt_create":"2025-12-26T02:25:16+08:00","gmt_modified":"2025-12-26T02:25:16+08:00"},{"catalog_id":"cb56a06a-5e53-4679-9b73-2df6b523a004","title":"命令执行处理器","description":"command-process","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"35c97c2a-d186-402b-ad2b-690c55c3ecf7","gmt_create":"2025-12-26T02:25:25+08:00","gmt_modified":"2025-12-26T02:25:25+08:00"},{"catalog_id":"ca1a83a9-76e4-4b39-989a-87f57d2ef7e2","title":"执行服务实现","description":"execution-service","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"748bfabd-e76b-41f5-9ce8-07624bd06e7a","gmt_create":"2025-12-26T02:25:36+08:00","gmt_modified":"2025-12-26T02:25:36+08:00"},{"catalog_id":"d19dc89c-4ae8-49c4-b55a-71e8b3fd7b6d","title":"用户管理","description":"ui-user","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"15477812-7595-4f8d-a82a-4fa4dde2747c","gmt_create":"2025-12-26T02:26:57+08:00","gmt_modified":"2025-12-26T02:26:57+08:00"},{"catalog_id":"aa4c55ae-1c79-4840-8841-48bcf9748aa5","title":"Livy执行引擎","description":"livy-engine","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"db3c79fc-35bb-4178-8c4a-6adc34d30c51","gmt_create":"2025-12-26T02:26:58+08:00","gmt_modified":"2025-12-26T02:26:58+08:00"},{"catalog_id":"4ef7f039-bb4a-4467-a957-9d7d0b44f9db","title":"Trino配置","description":"trino-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"da35c37b-1153-4546-9751-ef8a3ac57c44","gmt_create":"2025-12-26T02:27:17+08:00","gmt_modified":"2025-12-26T02:27:17+08:00"},{"catalog_id":"f6af807f-13d9-400a-93b9-c47c59471da6","title":"工作空间与租户API","description":"api-workspace","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b89ce464-cf1c-46af-aab3-e34fd02aebb6","gmt_create":"2025-12-26T02:28:19+08:00","gmt_modified":"2025-12-26T02:28:19+08:00"},{"catalog_id":"90618369-350f-4168-9952-0af519aa0add","title":"SQL Server配置","description":"sqlserver-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"894883c0-de57-4ca3-89b0-908aa758c81c","gmt_create":"2025-12-26T02:28:36+08:00","gmt_modified":"2025-12-26T02:28:36+08:00"},{"catalog_id":"9c3d0cc6-4854-41f9-ae0c-718080bd9671","title":"告警服务实现","description":"notification-service","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1c5407f7-ee26-46e6-b082-c1e066573b4d","gmt_create":"2025-12-26T02:28:44+08:00","gmt_modified":"2025-12-26T02:28:44+08:00"},{"catalog_id":"72541630-5f9d-45e9-8334-328fded1f2b4","title":"Presto配置","description":"presto-configuration","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3d96011f-daf4-40e6-bca1-e3490a1e7860","gmt_create":"2025-12-26T02:29:25+08:00","gmt_modified":"2025-12-26T02:29:25+08:00"},{"catalog_id":"a17f3c03-ab3a-47ea-b7e2-d23375e4be7e","title":"任务执行与监控API","description":"api-execution","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d32b616a-5dba-4c37-bbab-ab6fc77f7e8e","gmt_create":"2025-12-26T02:29:52+08:00","gmt_modified":"2025-12-26T02:29:52+08:00"},{"catalog_id":"856929d2-8ddc-4c0e-af3e-68de8ba55104","title":"请求处理机制","description":"request-processing","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"de25e484-ea48-4307-bc89-f606b2cd0894","gmt_create":"2025-12-26T02:30:33+08:00","gmt_modified":"2025-12-26T02:30:33+08:00"},{"catalog_id":"2666064b-e1fa-44a2-8343-842479eb3580","title":"任务参数构建","description":"parameter-construction","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"627dbd19-e83f-45f8-9237-99c8d8d373d8","gmt_create":"2025-12-26T02:30:37+08:00","gmt_modified":"2025-12-26T02:30:37+08:00"},{"catalog_id":"882a7389-2ff1-4f8e-b288-24894ae6574d","title":"跨表准确性检查","description":"multi-table-accuracy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"f1427ab0-5c01-464f-8de0-5b49365d4e5f","gmt_create":"2025-12-26T02:31:41+08:00","gmt_modified":"2025-12-26T02:31:41+08:00"},{"catalog_id":"09f31c8b-d5a0-42f2-89d2-20bc6aa19b0c","title":"基础属性检查","description":"basic-attribute-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"63a5129a-d045-4d19-ace1-5452184100f3","gmt_create":"2025-12-26T02:32:14+08:00","gmt_modified":"2025-12-26T02:32:14+08:00"},{"catalog_id":"0ef347bb-fa3e-4159-9059-20d0f3a6427b","title":"执行上下文管理","description":"context-management","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"409af96f-a3a0-4221-ace7-a04228d4a3d1","gmt_create":"2025-12-26T02:32:17+08:00","gmt_modified":"2025-12-26T02:32:17+08:00"},{"catalog_id":"5693cd4e-7ec5-4841-92d3-413cbcf7d614","title":"非空/空值检查","description":"null-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"1f7a3e10-52e7-4d11-b4e6-33e1b5381a41","gmt_create":"2025-12-26T02:34:24+08:00","gmt_modified":"2025-12-26T02:34:24+08:00"},{"catalog_id":"7a1f4b3f-875f-4546-81bc-adcfef66aa39","title":"跨表准确性检查","description":"multi-table-accuracy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"2fe4c058-0523-446b-b3e1-dd59a2c1536d","gmt_create":"2025-12-26T02:34:34+08:00","gmt_modified":"2025-12-26T02:34:34+08:00"},{"catalog_id":"6e843862-8b0b-4c13-af7f-449ef45aadd7","title":"日平均值策略","description":"daily-avg-strategy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0f2ded6e-1226-4320-a357-8c54989fba03","gmt_create":"2025-12-26T02:34:58+08:00","gmt_modified":"2025-12-26T02:34:58+08:00"},{"catalog_id":"7365a2cc-1450-46cd-931f-34fcf055a743","title":"响应结果转换","description":"response-conversion","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"7727b690-847c-42b0-bbf0-8107f2952869","gmt_create":"2025-12-26T02:35:46+08:00","gmt_modified":"2025-12-26T02:35:46+08:00"},{"catalog_id":"fe71d112-2892-4cfb-a3fe-29e5f6327941","title":"命令分发机制","description":"command-distribution","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"cb40aa69-fda3-4429-ab6f-d7f39e2213f9","gmt_create":"2025-12-26T02:36:36+08:00","gmt_modified":"2025-12-26T02:36:36+08:00"},{"catalog_id":"945bb726-f31e-4e2d-98c1-70c28d3af058","title":"两表值比较检查","description":"two-table-value-comparison","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0ebc888a-93b4-465f-80b5-a4939fc4d487","gmt_create":"2025-12-26T02:37:13+08:00","gmt_modified":"2025-12-26T02:37:13+08:00"},{"catalog_id":"b86c636d-d0ec-4620-8685-e1cb0a98cbb2","title":"状态消息通信","description":"message-communication","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"5a456cd1-6974-4e5a-be4c-9ff055620233","gmt_create":"2025-12-26T02:37:50+08:00","gmt_modified":"2025-12-26T02:37:50+08:00"},{"catalog_id":"85518fd2-a28a-4b69-8ecc-ff43752cac85","title":"统计特征检查","description":"statistical-characteristics-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"12e408dc-3b6e-4f97-93ca-1949ee8bcd04","gmt_create":"2025-12-26T02:38:30+08:00","gmt_modified":"2025-12-26T02:38:30+08:00"},{"catalog_id":"2e5e0a8b-fcca-44c4-869b-60a9720e3449","title":"两表值比较检查","description":"two-table-value-comparison","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"c456e2c2-94e1-40f7-97b0-8c8c5909e1da","gmt_create":"2025-12-26T08:11:30+08:00","gmt_modified":"2025-12-26T08:11:30+08:00"},{"catalog_id":"124ac55f-1c6c-431f-8ee1-bcb309cc1a47","title":"唯一性/重复值检查","description":"uniqueness-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"7cc59d19-2ab9-48b8-96d6-bd193d05f787","gmt_create":"2025-12-26T08:11:36+08:00","gmt_modified":"2025-12-26T08:11:36+08:00"},{"catalog_id":"7f81e91d-4a21-4be6-b32c-a343de2727d9","title":"错误处理策略","description":"error-handling","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"0a55bfbc-e3af-4c06-b845-7faa5c899111","gmt_create":"2025-12-26T08:13:01+08:00","gmt_modified":"2026-02-05T02:06:52.2906492+08:00"},{"catalog_id":"c35785d4-cafd-424b-9de1-d536b2b5016c","title":"执行触发流程","description":"execution-trigger","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"b698bd7e-c6ec-4ba2-85cc-c83480843723","gmt_create":"2025-12-26T08:13:17+08:00","gmt_modified":"2025-12-26T08:13:17+08:00"},{"catalog_id":"bc3ea374-b5d2-4353-95ed-77e764c7f7fd","title":"异常传播与处理","description":"exception-handling","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ba4f7804-366b-4b10-8ae8-bf7d65ebbba1","gmt_create":"2025-12-26T08:14:12+08:00","gmt_modified":"2025-12-26T08:14:13+08:00"},{"catalog_id":"93352bfb-74c6-4843-8c91-6b3e2e0e11d3","title":"业务规则检查","description":"business-rule-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"79a82e7b-0774-4c52-abbd-2680ff55d2ff","gmt_create":"2025-12-26T08:14:37+08:00","gmt_modified":"2025-12-26T08:14:37+08:00"},{"catalog_id":"64444bcd-fb4d-4b0a-b358-501356c800e3","title":"数值范围检查","description":"value-range-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"12d17ea6-da6e-4c48-ba14-99ce7175386c","gmt_create":"2025-12-26T08:15:48+08:00","gmt_modified":"2025-12-26T08:15:48+08:00"},{"catalog_id":"3b8d6652-6da6-44d6-a1aa-52533177a601","title":"月平均值策略","description":"monthly-avg-strategy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"e17edb1f-d955-4db5-9993-731414776b25","gmt_create":"2025-12-26T08:16:45+08:00","gmt_modified":"2025-12-26T08:16:45+08:00"},{"catalog_id":"9805acb1-5a4e-431f-b588-628b8212df88","title":"统计指标检查","description":"statistical-checks","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"533f36a4-75e2-44f5-9f14-a0603e88878c","gmt_create":"2025-12-26T08:16:57+08:00","gmt_modified":"2025-12-26T08:16:57+08:00"},{"catalog_id":"ba0be7d5-aa3d-429f-8967-cbbbe9a92afa","title":"最近N天平均值策略","description":"last-n-day-avg-strategy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"3be4d28c-202d-427a-a36d-f7578aa626c2","gmt_create":"2025-12-26T08:18:41+08:00","gmt_modified":"2025-12-26T08:18:41+08:00"},{"catalog_id":"d949eab0-e738-4746-91b5-0356c783ba8e","title":"周平均值策略","description":"weekly-avg-strategy","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"ee9789b8-522f-419a-a1e7-8f0a03ec6e7d","gmt_create":"2025-12-26T08:32:28+08:00","gmt_modified":"2025-12-26T08:32:28+08:00"},{"catalog_id":"e2c0779e-bb1b-4aea-bacd-3677c0c70053","title":"Doris连接器","description":"doris-connector","extend":"{}","progress_status":"completed","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","id":"d99205fd-d456-4d7d-91b1-4141f45dda95","gmt_create":"2026-01-29T21:51:04.6793062+08:00","gmt_modified":"2026-01-29T21:51:04.681309+08:00"}],"wiki_overview":{"content":"\u003cblog\u003e\n# DataVines 项目综合分析\n\n## 1. 项目介绍\n\nDataVines 是一个易于使用的数据质量服务化平台,专注于确保数据在集成和处理过程中的准确性。作为 DataOps 的核心组件,该平台支持多种数据质量度量和监控功能。\n\n### 项目目标\n- 提供全面的数据质量管理解决方案\n- 支持多种数据源的连接和监控\n- 实现数据质量检查规则的灵活配置和扩展\n- 提供多样的告警通道和结果通知机制\n- 支持分布式部署和高可用性架构\n\n### 目标用户\n- 数据工程师\n- 数据质量管理人员\n- 大数据平台运维人员\n- 数据治理团队\n\n## 2. 技术架构\n\n### 组件分解\n\nDataVines 采用模块化设计,主要由以下核心组件构成:\n\n```mermaid\nflowchart TD\n A[前端UI] --\u003e B[Server服务]\n B --\u003e C[执行引擎]\n B --\u003e D[连接器]\n B --\u003e E[通知系统]\n B --\u003e F[注册中心]\n C --\u003e G[Spark引擎]\n C --\u003e H[Local引擎]\n D --\u003e I[JDBC连接器]\n D --\u003e J[文件连接器]\n D --\u003e K[NoSQL连接器]\n E --\u003e L[邮件通知]\n E --\u003e M[钉钉通知]\n F --\u003e N[MySQL注册]\n F --\u003e O[ZooKeeper注册]\n```\n\n### 设计模式\n\n项目采用了多种设计模式:\n- **插件化设计**:通过 SPI 机制实现各模块的可扩展性\n- **微内核架构**:核心服务与功能模块分离\n- **事件驱动**:任务调度和状态变更通过事件机制处理\n- **工厂模式**:连接器、执行器等组件通过工厂创建\n\n### 系统关系\n\n```mermaid\ngraph TD\n UI[Web UI] --\u003e Server[DataVines Server]\n CLI[命令行工具] --\u003e Server\n Server --\u003e Registry[注册中心]\n Server --\u003e Scheduler[任务调度器]\n Server --\u003e Executor[任务执行器]\n Executor --\u003e Engine[执行引擎]\n Engine --\u003e Connector[数据连接器]\n Connector --\u003e DataSource[数据源]\n Server --\u003e Notification[通知系统]\n Notification --\u003e Email[邮件]\n Notification --\u003e DingTalk[钉钉]\n Notification --\u003e WeCom[企业微信]\n```\n\n### 数据流\n\n```mermaid\nflowchart LR\n A[用户配置] --\u003e B[Server接收请求]\n B --\u003e C[生成任务命令]\n C --\u003e D[任务调度器]\n D --\u003e E[任务执行管理器]\n E --\u003e F[选择执行引擎]\n F --\u003e G[执行数据质量检查]\n G --\u003e H[获取检查结果]\n H --\u003e I[结果验证]\n I --\u003e J{是否异常?}\n J --\u003e|是| K[触发告警]\n J --\u003e|否| L[记录正常结果]\n K --\u003e M[通知系统]\n M --\u003e N[多种告警渠道]\n```\n\n## 3. 关键实现\n\n### 主要入口点\n- 服务启动类:`datavines-server/src/main/java/io/datavines/server/DataVinesServer.java`\n- 任务执行类:`datavines-runner/src/main/java/io/datavines/runner/JobRunner.java`\n\n### 核心模块\n- **datavines-server**:核心服务模块,负责任务调度和管理\n- **datavines-engine**:执行引擎模块,支持多种计算框架\n- **datavines-connector**:数据连接器模块,支持多种数据源\n- **datavines-metric**:度量指标模块,提供数据质量检查规则\n- **datavines-notification**:通知模块,支持多种告警方式\n\n### 配置方法\n- 主要配置文件:`datavines-server/src/main/resources/application.yaml`\n- 插件配置通过 SPI 机制实现\n- 运行时配置通过属性文件和环境变量管理\n\n### 外部依赖\n- 数据库:MySQL、PostgreSQL\n- 计算引擎:Spark、Flink\n- 注册中心:ZooKeeper、MySQL\n- 消息通知:邮件、钉钉、飞书、企业微信\n\n### 集成点\n- REST API 接口用于外部系统集成\n- 命令行工具支持脚本化操作\n- 插件机制支持自定义扩展\n\n### 组件关系\n\n```mermaid\ngraph LR\n Server[DataVines Server] --\u003e|调用| Engine[执行引擎]\n Server --\u003e|存储| Registry[注册中心]\n Server --\u003e|发送| Notification[通知系统]\n Engine --\u003e|连接| Connector[数据连接器]\n Connector --\u003e|访问| DataSource[外部数据源]\n Engine --\u003e|执行| Spark[Spark引擎]\n Engine --\u003e|执行| Local[Local引擎]\n Notification --\u003e|发送| Email[邮件]\n Notification --\u003e|发送| IM[即时通讯]\n```\n\n## 4. 关键特性\n\n### 功能概述\n- **数据目录**:自动获取数据源元数据,构建数据目录\n- **数据质量**:内置27种数据质量检查规则\n- **数据画像**:定时执行数据检测,输出数据画像报告\n- **插件设计**:支持多种模块的用户自定义插件扩展\n\n### 实现亮点\n- **多执行模式**:支持 Web 页面配置和命令行提交\n- **高可用设计**:支持水平扩展和自动容错\n- **灵活的检查规则**:支持单表列检查、自定义SQL检查、跨表准确性检查等\n- **丰富的连接器**:支持 MySQL、Impala、StarRocks、Doris、Presto、Trino、ClickHouse、PostgreSQL 等多种数据源\n\n### 特性架构\n\n```mermaid\nstateDiagram-v2\n [*] --\u003e Idle\n Idle --\u003e Configuring: 用户配置任务\n Configuring --\u003e Scheduling: 保存配置\n Scheduling --\u003e Executing: 调度器触发\n Executing --\u003e Checking: 执行数据质量检查\n Checking --\u003e Validating: 验证检查结果\n Validating --\u003e Success: 结果正常\n Validating --\u003e Alerting: 结果异常\n Success --\u003e Idle: 记录结果\n Alerting --\u003e Notifying: 发送告警\n Notifying --\u003e Idle: 完成通知\n Executing --\u003e Failed: 执行失败\n Failed --\u003e Retry: 重试机制\n Retry --\u003e Executing: 重新执行\n```\n\nSources:\n- [README.md](README.md)\n- [DataVinesServer.java](datavines-server/src/main/java/io/datavines/server/DataVinesServer.java)\n- [JobRunner.java](datavines-runner/src/main/java/io/datavines/runner/JobRunner.java)\n- [application.yaml](datavines-server/src/main/resources/application.yaml)\n\u003c/blog\u003e","gmt_create":"2025-12-25T23:38:56+08:00","gmt_modified":"2025-12-25T23:38:56+08:00","id":"bea20166-fe58-4e2d-8406-c02fe71d09e4","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc"},"wiki_readme":{"content":"No readme file","gmt_create":"2025-12-25T23:37:06+08:00","gmt_modified":"2025-12-25T23:37:06+08:00","id":"9c3ff51f-be15-4e26-820e-b668fd883a83","repo_id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc"},"wiki_repo":{"id":"bd38f909-70c7-4a22-94d1-60083e2b8ebc","name":"datavines","progress_status":"completed","wiki_present_status":"COMPLETED","optimized_catalog":"\".\\n├── bin\\\\\\n│ ├── datavines-daemon.sh\\n│ └── datavines-submit.sh\\n├── datavines-cli\\\\\\n│ └── pom.xml\\n├── datavines-client\\\\\\n│ ├── datavines-http-client\\\\\\n│ │ ├── datavines-http-client-core\\\\\\n│ │ │ ├── src\\\\\\n│ │ │ │ ├── main\\\\java\\\\io\\\\datavines\\\\http\\\\client\\\\\\n│ │ │ │ │ └── ... 1 files, 3 dirs not shown\\n│ │ │ │ ├── test\\\\java\\\\io\\\\datavines\\\\http\\\\clinet\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ └── pom.xml\\n│ └── pom.xml\\n├── datavines-common\\\\\\n│ ├── src\\\\main\\\\\\n│ │ ├── java\\\\io\\\\datavines\\\\common\\\\\\n│ │ │ ├── config\\\\\\n│ │ │ │ ├── enums\\\\\\n│ │ │ │ │ └── ... 3 files, 0 dirs not shown\\n│ │ │ │ ├── BaseConfig.java\\n│ │ │ │ ├── CheckResult.java\\n│ │ │ │ ├── Config.java\\n│ │ │ │ ├── ConfigChecker.java\\n│ │ │ │ ├── ConfigRuntimeException.java\\n│ │ │ │ ├── Configurations.java\\n│ │ │ │ ├── CoreConfig.java\\n│ │ │ │ ├── DataVinesJobConfig.java\\n│ │ │ │ ├── EnvConfig.java\\n│ │ │ │ ├── IConfig.java\\n│ │ │ │ ├── SinkConfig.java\\n│ │ │ │ ├── SourceConfig.java\\n│ │ │ │ └── TransformConfig.java\\n│ │ │ ├── datasource\\\\jdbc\\\\\\n│ │ │ │ ├── entity\\\\\\n│ │ │ │ │ └── ... 4 files, 0 dirs not shown\\n│ │ │ │ ├── utils\\\\\\n│ │ │ │ │ └── ... 3 files, 0 dirs not shown\\n│ │ │ │ ├── BaseJdbcDataSourceInfo.java\\n│ │ │ │ ├── IJdbcDataSourceInfo.java\\n│ │ │ │ ├── JdbcConnectionInfo.java\\n│ │ │ │ ├── JdbcDataSourceInfoManager.java\\n│ │ │ │ ├── JdbcDataSourceManager.java\\n│ │ │ │ ├── JdbcExecutorClient.java\\n│ │ │ │ └── JdbcExecutorClientManager.java\\n│ │ │ ├── entity\\\\\\n│ │ │ │ ├── job\\\\\\n│ │ │ │ │ └── ... 6 files, 0 dirs not shown\\n│ │ │ │ ├── ConnectionInfo.java\\n│ │ │ │ ├── ConnectorParameter.java\\n│ │ │ │ ├── ExecuteSql.java\\n│ │ │ │ ├── JobExecutionInfo.java\\n│ │ │ │ ├── JobExecutionParameter.java\\n│ │ │ │ ├── JobExecutionRequest.java\\n│ │ │ │ ├── ListWithQueryColumn.java\\n│ │ │ │ ├── LogResult.java\\n│ │ │ │ ├── MappingColumn.java\\n│ │ │ │ ├── ProcessResult.java\\n│ │ │ │ ├── QueryColumn.java\\n│ │ │ │ ├── SparkEngineParameter.java\\n│ │ │ │ └── TokenInfo.java\\n│ │ │ ├── enums\\\\\\n│ │ │ │ ├── DataType.java\\n│ │ │ │ ├── DataVinesDataType.java\\n│ │ │ │ ├── EntityRelType.java\\n│ │ │ │ ├── ExecutionStatus.java\\n│ │ │ │ ├── JobType.java\\n│ │ │ │ ├── OperatorType.java\\n│ │ │ │ └── TimeoutStrategy.java\\n│ │ │ ├── exception\\\\\\n│ │ │ │ └── DataVinesException.java\\n│ │ │ ├── log\\\\\\n│ │ │ │ ├── JobExecutionLogDiscriminator.java\\n│ │ │ │ ├── JobExecutionLogFilter.java\\n│ │ │ │ ├── SensitiveDataConverter.java\\n│ │ │ │ └── ServerLogFilter.java\\n│ │ │ ├── param\\\\\\n│ │ │ │ ├── form\\\\\\n│ │ │ │ │ └── ... 7 files, 2 dirs not shown\\n│ │ │ │ ├── ConnectorRequestParam.java\\n│ │ │ │ ├── ConnectorResponse.java\\n│ │ │ │ ├── DeleteDataRequestParam.java\\n│ │ │ │ ├── ExecuteRequestParam.java\\n│ │ │ │ ├── GetColumnsRequestParam.java\\n│ │ │ │ ├── GetDataSourcesRequestParam.java\\n│ │ │ │ ├── GetDatabasesRequestParam.java\\n│ │ │ │ ├── GetTablesRequestParam.java\\n│ │ │ │ └── TestConnectionRequestParam.java\\n│ │ │ ├── utils\\\\\\n│ │ │ │ ├── placeholder\\\\\\n│ │ │ │ │ └── ... 3 files, 0 dirs not shown\\n│ │ │ │ ├── ArgsUtils.java\\n│ │ │ │ ├── CommonPropertyUtils.java\\n│ │ │ │ ├── ConnectionUtils.java\\n│ │ │ │ ├── CryptionUtils.java\\n│ │ │ │ ├── DateUtils.java\\n│ │ │ │ ├── FileUtils.java\\n│ │ │ │ ├── HttpUtils.java\\n│ │ │ │ ├── IOUtils.java\\n│ │ │ │ ├── JSONUtils.java\\n│ │ │ │ ├── JdbcUrlParser.java\\n│ │ │ │ ├── LoggerUtils.java\\n│ │ │ │ ├── Md5Utils.java\\n│ │ │ │ ├── NetUtils.java\\n│ │ │ │ ├── OSUtils.java\\n│ │ │ │ ├── ParameterUtils.java\\n│ │ │ │ ├── PasswordFilterUtils.java\\n│ │ │ │ ├── ProcessUtils.java\\n│ │ │ │ ├── SensitiveLogUtils.java\\n│ │ │ │ ├── Stopper.java\\n│ │ │ │ ├── StringUtils.java\\n│ │ │ │ ├── ThreadUtils.java\\n│ │ │ │ ├── TypesafeConfigUtils.java\\n│ │ │ │ └── YarnUtils.java\\n│ │ │ ├── zookeeper\\\\\\n│ │ │ │ ├── DefaultEnsembleProvider.java\\n│ │ │ │ ├── ZooKeeperClient.java\\n│ │ │ │ └── ZooKeeperConfig.java\\n│ │ │ ├── CommonConstants.java\\n│ │ │ └── ConfigConstants.java\\n│ │ └── resources\\\\\\n│ │ └── common.properties\\n│ └── pom.xml\\n├── datavines-connector\\\\\\n│ ├── datavines-connector-api\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\connector\\\\api\\\\\\n│ │ │ ├── entity\\\\\\n│ │ │ │ ├── ColumnLineage.java\\n│ │ │ │ ├── JdbcOptions.java\\n│ │ │ │ ├── MetaDataConstants.java\\n│ │ │ │ ├── QueryColumn.java\\n│ │ │ │ ├── ResultList.java\\n│ │ │ │ ├── ResultListWithColumns.java\\n│ │ │ │ ├── ScriptMetadata.java\\n│ │ │ │ ├── StatementMetadata.java\\n│ │ │ │ ├── StatementMetadataFragment.java\\n│ │ │ │ └── StructField.java\\n│ │ │ ├── utils\\\\\\n│ │ │ │ ├── JdbcUtils.java\\n│ │ │ │ └── SqlUtils.java\\n│ │ │ ├── ConfigBuilder.java\\n│ │ │ ├── Connector.java\\n│ │ │ ├── ConnectorFactory.java\\n│ │ │ ├── DataSourceClient.java\\n│ │ │ ├── Dialect.java\\n│ │ │ ├── Executor.java\\n│ │ │ ├── LineageParser.java\\n│ │ │ ├── MetricScript.java\\n│ │ │ ├── ParameterConverter.java\\n│ │ │ ├── ResponseConverter.java\\n│ │ │ ├── StatementParser.java\\n│ │ │ ├── StatementSplitter.java\\n│ │ │ └── TypeConverter.java\\n│ │ └── pom.xml\\n│ ├── datavines-connector-plugins\\\\\\n│ │ ├── datavines-connector-all\\\\\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-clickhouse\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 9 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-databend\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 7 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-dm\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 7 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-doris\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 7 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-file\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 7 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-flink\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 3 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-hive\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 10 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-impala\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 7 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-jdbc\\\\\\n│ │ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ ├── AbstractJdbcConnectorFactory.java\\n│ │ │ │ ├── BaseJdbcExecutor.java\\n│ │ │ │ ├── DefaultStatementParser.java\\n│ │ │ │ ├── DefaultStatementSplitter.java\\n│ │ │ │ ├── JdbcConfigBuilder.java\\n│ │ │ │ ├── JdbcConnector.java\\n│ │ │ │ ├── JdbcDataSourceClient.java\\n│ │ │ │ ├── JdbcDialect.java\\n│ │ │ │ ├── JdbcMetricScript.java\\n│ │ │ │ ├── JdbcParameterConverter.java\\n│ │ │ │ ├── JdbcResponseConverter.java\\n│ │ │ │ └── JdbcTypeConverter.java\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-mongodb\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 8 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-mysql\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 8 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-oracle\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 9 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-postgresql\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 9 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-presto\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 8 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-spark\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 3 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-sqlserver\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 8 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-starrocks\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 7 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-connector-trino\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ ├── java\\\\io\\\\datavines\\\\connector\\\\plugin\\\\\\n│ │ │ │ │ └── ... 8 files, 0 dirs not shown\\n│ │ │ │ ├── resources\\\\META-INF\\\\plugins\\\\\\n│ │ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ └── pom.xml\\n│ └── pom.xml\\n├── datavines-core\\\\\\n│ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\core\\\\\\n│ │ ├── aop\\\\\\n│ │ │ ├── RefreshToken.java\\n│ │ │ └── RefreshTokenAop.java\\n│ │ ├── constant\\\\\\n│ │ │ └── DataVinesConstants.java\\n│ │ ├── entity\\\\\\n│ │ │ └── ResultMap.java\\n│ │ ├── enums\\\\\\n│ │ │ └── Status.java\\n│ │ ├── exception\\\\\\n│ │ │ └── DataVinesServerException.java\\n│ │ └── utils\\\\\\n│ │ ├── BeanConvertUtils.java\\n│ │ ├── LanguageUtils.java\\n│ │ └── TokenManager.java\\n│ └── pom.xml\\n├── datavines-dist\\\\\\n│ ├── src\\\\main\\\\assembly\\\\\\n│ │ └── datavines-bin.xml\\n│ └── pom.xml\\n├── datavines-engine\\\\\\n│ ├── datavines-engine-api\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\engine\\\\api\\\\\\n│ │ │ ├── component\\\\\\n│ │ │ │ └── Component.java\\n│ │ │ ├── engine\\\\\\n│ │ │ │ └── EngineExecutor.java\\n│ │ │ ├── env\\\\\\n│ │ │ │ ├── Execution.java\\n│ │ │ │ └── RuntimeEnvironment.java\\n│ │ │ ├── plugin\\\\\\n│ │ │ │ └── Plugin.java\\n│ │ │ └── EngineConstants.java\\n│ │ └── pom.xml\\n│ ├── datavines-engine-common\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\engine\\\\common\\\\utils\\\\\\n│ │ │ ├── ParserUtils.java\\n│ │ │ └── QuoteIdentifier.java\\n│ │ ├── .gitignore\\n│ │ └── pom.xml\\n│ ├── datavines-engine-config\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\engine\\\\config\\\\\\n│ │ │ ├── BaseJobConfigurationBuilder.java\\n│ │ │ ├── DataVinesConfigurationManager.java\\n│ │ │ ├── JobConfigurationBuilder.java\\n│ │ │ └── MetricParserUtils.java\\n│ │ ├── README.md\\n│ │ └── pom.xml\\n│ ├── datavines-engine-core\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\engine\\\\core\\\\\\n│ │ │ ├── config\\\\\\n│ │ │ │ └── ConfigParser.java\\n│ │ │ ├── utils\\\\\\n│ │ │ │ └── JsonUtils.java\\n│ │ │ └── BaseDataVinesBootstrap.java\\n│ │ ├── README.md\\n│ │ └── pom.xml\\n│ ├── datavines-engine-executor\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\engine\\\\executor\\\\core\\\\\\n│ │ │ ├── base\\\\\\n│ │ │ │ ├── AbstractEngineExecutor.java\\n│ │ │ │ ├── AbstractLivyEngineExecutor.java\\n│ │ │ │ └── AbstractYarnEngineExecutor.java\\n│ │ │ ├── enums\\\\\\n│ │ │ │ ├── LivyStates.java\\n│ │ │ │ └── ResourceSchedulePlatformType.java\\n│ │ │ ├── executor\\\\\\n│ │ │ │ ├── BaseCommandProcess.java\\n│ │ │ │ ├── LivyCommandProcess.java\\n│ │ │ │ └── ShellCommandProcess.java\\n│ │ │ └── helper\\\\\\n│ │ │ └── LivyTaskSubmitHelper.java\\n│ │ └── pom.xml\\n│ ├── datavines-engine-plugins\\\\\\n│ │ ├── datavines-engine-flink\\\\\\n│ │ │ ├── datavines-engine-flink-api\\\\\\n│ │ │ │ ├── src\\\\main\\\\\\n│ │ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ │ ├── pom.xml\\n│ │ │ │ └── ... 0 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-flink-config\\\\\\n│ │ │ │ ├── src\\\\main\\\\\\n│ │ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ │ ├── pom.xml\\n│ │ │ │ └── ... 0 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-flink-connector-jdbc\\\\\\n│ │ │ │ ├── src\\\\main\\\\\\n│ │ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ │ ├── pom.xml\\n│ │ │ │ └── ... 0 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-flink-core\\\\\\n│ │ │ │ ├── src\\\\main\\\\\\n│ │ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ │ ├── pom.xml\\n│ │ │ │ └── ... 0 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-flink-executor\\\\\\n│ │ │ │ ├── src\\\\main\\\\\\n│ │ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ │ ├── pom.xml\\n│ │ │ │ └── ... 0 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-flink-transform-sql\\\\\\n│ │ │ │ ├── src\\\\main\\\\\\n│ │ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ │ ├── pom.xml\\n│ │ │ │ └── ... 0 files, 1 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-engine-livy\\\\\\n│ │ │ ├── datavines-engine-livy-executor\\\\\\n│ │ │ │ ├── src\\\\main\\\\\\n│ │ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ │ ├── pom.xml\\n│ │ │ │ └── ... 0 files, 1 dirs not shown\\n│ │ │ ├── README.md\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-engine-local\\\\\\n│ │ │ ├── datavines-engine-local-api\\\\\\n│ │ │ │ ├── src\\\\main\\\\\\n│ │ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ │ ├── pom.xml\\n│ │ │ │ └── ... 0 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-local-config\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-local-connector-file\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-local-connector-jdbc\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-local-core\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-local-executor\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-local-transform\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-engine-spark\\\\\\n│ │ │ ├── datavines-engine-spark-api\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-spark-config\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-spark-connector-file\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── datavines-engine-spark-connector-jdbc\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-spark-connector-mongodb\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-spark-core\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-spark-executor\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ ├── datavines-engine-spark-transform-sql\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ └── pom.xml\\n│ ├── README.md\\n│ └── pom.xml\\n├── datavines-metric\\\\\\n│ ├── datavines-metric-api\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\metric\\\\api\\\\\\n│ │ │ ├── ColumnInfo.java\\n│ │ │ ├── ConfigItem.java\\n│ │ │ ├── ExpectedValue.java\\n│ │ │ ├── MetricActualValueType.java\\n│ │ │ ├── MetricConstants.java\\n│ │ │ ├── MetricDimension.java\\n│ │ │ ├── MetricDirectionType.java\\n│ │ │ ├── MetricExecutionResult.java\\n│ │ │ ├── MetricLevel.java\\n│ │ │ ├── MetricType.java\\n│ │ │ ├── MetricValidator.java\\n│ │ │ ├── ResultFormula.java\\n│ │ │ ├── ResultFormulaType.java\\n│ │ │ └── SqlMetric.java\\n│ │ └── pom.xml\\n│ ├── datavines-metric-expected-plugins\\\\\\n│ │ ├── datavines-metric-expected-all\\\\\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-base\\\\\\n│ │ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\metric\\\\expected\\\\plugin\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-daily-avg\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-fix\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-last30day-avg\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-last7day-avg\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-monthly-avg\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-none\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ ├── .gitignore\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-table-rows\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-target-table-rows\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-expected-weekly-avg\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ └── pom.xml\\n│ ├── datavines-metric-plugins\\\\\\n│ │ ├── datavines-metric-all\\\\\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-base\\\\\\n│ │ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\metric\\\\plugin\\\\base\\\\\\n│ │ │ │ └── ... 3 files, 0 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-avg\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-avg-length\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-blank\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-distinct\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-duplicate\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-histogram\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-in-enums\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-length\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-match-not-regex\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-match-regex\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-max\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-max-length\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-min\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-min-length\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-not-in-enums\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-not-null\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-null\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-std-dev\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-sum\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-unique\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-value-between\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-column-variance\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-custom-aggregate-sql\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-multi-table-accuracy\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-multi-table-value-comparison\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-table-freshness\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-table-row-count\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ └── pom.xml\\n│ ├── datavines-metric-result-formula-plugins\\\\\\n│ │ ├── datavines-metric-result-formula-all\\\\\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-result-formula-count\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-result-formula-diff\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-result-formula-diff-actual-expected\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ ├── .gitignore\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-result-formula-diff-percentage\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-metric-result-formula-percentage\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ └── pom.xml\\n│ └── pom.xml\\n├── datavines-notification\\\\\\n│ ├── datavines-notification-api\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\notification\\\\api\\\\\\n│ │ │ ├── constants\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── entity\\\\\\n│ │ │ │ └── ... 5 files, 0 dirs not shown\\n│ │ │ └── spi\\\\\\n│ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ └── pom.xml\\n│ ├── datavines-notification-core\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\notification\\\\core\\\\\\n│ │ │ ├── client\\\\\\n│ │ │ │ └── ... 1 files, 1 dirs not shown\\n│ │ │ └── NotificationManager.java\\n│ │ └── pom.xml\\n│ ├── datavines-notification-plugins\\\\\\n│ │ ├── datavines-notification-plugin-dingtalk\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-notification-plugin-email\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-notification-plugin-lark\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-notification-plugin-wecombot\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ └── pom.xml\\n│ └── pom.xml\\n├── datavines-registry\\\\\\n│ ├── datavines-registry-api\\\\\\n│ │ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\registry\\\\api\\\\\\n│ │ │ ├── ConnectionListener.java\\n│ │ │ ├── ConnectionStatus.java\\n│ │ │ ├── Event.java\\n│ │ │ ├── Registry.java\\n│ │ │ ├── RegistryException.java\\n│ │ │ ├── ServerInfo.java\\n│ │ │ └── SubscribeListener.java\\n│ │ └── pom.xml\\n│ ├── datavines-registry-plugins\\\\\\n│ │ ├── datavines-registry-mysql\\\\\\n│ │ │ ├── src\\\\main\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ ├── datavines-registry-zookeeper\\\\\\n│ │ │ ├── src\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ └── pom.xml\\n│ │ └── pom.xml\\n│ └── pom.xml\\n├── datavines-runner\\\\\\n│ ├── src\\\\main\\\\\\n│ │ ├── java\\\\io\\\\datavines\\\\runner\\\\\\n│ │ │ ├── JobExecuteBootstrap.java\\n│ │ │ └── JobRunner.java\\n│ │ └── resources\\\\\\n│ │ ├── submit_job_file_source.json\\n│ │ ├── submit_job_file_storage.json\\n│ │ └── submit_job_mysql_storage.json\\n│ └── pom.xml\\n├── datavines-server\\\\\\n│ ├── src\\\\main\\\\\\n│ │ ├── java\\\\io\\\\datavines\\\\server\\\\\\n│ │ │ ├── api\\\\\\n│ │ │ │ └── ... 0 files, 5 dirs not shown\\n│ │ │ ├── config\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── dqc\\\\\\n│ │ │ │ └── ... 0 files, 3 dirs not shown\\n│ │ │ ├── enums\\\\\\n│ │ │ │ └── ... 15 files, 0 dirs not shown\\n│ │ │ ├── registry\\\\\\n│ │ │ │ └── ... 2 files, 0 dirs not shown\\n│ │ │ ├── repository\\\\\\n│ │ │ │ └── ... 0 files, 3 dirs not shown\\n│ │ │ ├── scheduler\\\\\\n│ │ │ │ └── ... 7 files, 2 dirs not shown\\n│ │ │ ├── utils\\\\\\n│ │ │ │ └── ... 7 files, 0 dirs not shown\\n│ │ │ └── DataVinesServer.java\\n│ │ └── resources\\\\\\n│ │ ├── jmx\\\\\\n│ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ ├── mapper\\\\\\n│ │ │ └── ... 14 files, 0 dirs not shown\\n│ │ ├── application.yaml\\n│ │ └── server-logback.xml\\n│ ├── README.md\\n│ └── pom.xml\\n├── datavines-spi\\\\\\n│ ├── src\\\\main\\\\java\\\\io\\\\datavines\\\\spi\\\\\\n│ │ ├── utils\\\\\\n│ │ │ ├── ClassUtils.java\\n│ │ │ ├── Holder.java\\n│ │ │ └── UnsafeStringWriter.java\\n│ │ ├── PluginLoader.java\\n│ │ ├── Prioritized.java\\n│ │ └── SPI.java\\n│ └── pom.xml\\n├── datavines-ui\\\\\\n│ ├── Editor\\\\\\n│ │ ├── common\\\\\\n│ │ │ ├── CustomSelect\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── FormRender\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── IF\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── PopConfirm\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useFormRender\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useImmutable\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useLoading\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useModal\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useMount\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── usePersistFn\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useUnMount\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useWatch\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ └── index.ts\\n│ │ ├── components\\\\\\n│ │ │ ├── Database\\\\\\n│ │ │ │ └── ... 5 files, 2 dirs not shown\\n│ │ │ ├── FlinkConfig\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── JobConfig\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── MetricModal\\\\\\n│ │ │ │ └── ... 5 files, 10 dirs not shown\\n│ │ │ ├── Monaco\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── SqlTable\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── Tree\\\\\\n│ │ │ │ └── ... 2 files, 1 dirs not shown\\n│ │ │ ├── index.less\\n│ │ │ └── index.tsx\\n│ │ ├── hooks\\\\\\n│ │ │ ├── useEditor\\\\\\n│ │ │ │ └── ... 2 files, 0 dirs not shown\\n│ │ │ ├── useMonaco\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useNotRequiredRule\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useRequest\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ └── useRequiredRule\\\\\\n│ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ ├── http\\\\\\n│ │ │ ├── create.ts\\n│ │ │ ├── index.tsx\\n│ │ │ ├── request.interceptor.ts\\n│ │ │ ├── response.interceptor.ts\\n│ │ │ └── type.ts\\n│ │ ├── locale\\\\\\n│ │ │ ├── en_US.ts\\n│ │ │ └── zh_CN.ts\\n│ │ ├── store\\\\\\n│ │ │ ├── createStore.tsx\\n│ │ │ └── editor.ts\\n│ │ ├── utils\\\\\\n│ │ │ └── index.ts\\n│ │ ├── index.less\\n│ │ ├── index.tsx\\n│ │ └── type.ts\\n│ ├── build\\\\\\n│ │ ├── .proxy.example.js\\n│ │ ├── utils.js\\n│ │ ├── webpack.common.js\\n│ │ ├── webpack.development.js\\n│ │ └── webpack.production.js\\n│ ├── public\\\\\\n│ │ ├── index-dev.html\\n│ │ └── index-prod.html\\n│ ├── src\\\\\\n│ │ ├── App\\\\\\n│ │ │ ├── ConfigProvider.tsx\\n│ │ │ └── index.tsx\\n│ │ ├── action\\\\\\n│ │ │ ├── sla\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ └── workSpace\\\\\\n│ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ ├── common\\\\\\n│ │ │ └── index.ts\\n│ │ ├── component\\\\\\n│ │ │ ├── ContentLayout\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── GoBack\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── Header\\\\\\n│ │ │ │ └── ... 2 files, 3 dirs not shown\\n│ │ │ ├── Menu\\\\\\n│ │ │ │ └── ... 0 files, 2 dirs not shown\\n│ │ │ ├── SearchForm\\\\\\n│ │ │ │ └── ... 2 files, 0 dirs not shown\\n│ │ │ ├── SwitchLanguage\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── Title\\\\\\n│ │ │ │ └── ... 2 files, 0 dirs not shown\\n│ │ │ ├── KeepAlive.tsx\\n│ │ │ └── index.tsx\\n│ │ ├── hooks\\\\\\n│ │ │ ├── CountDown\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useDetailPage\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useMainInitData\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── useVerificationCode\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ └── index.ts\\n│ │ ├── http\\\\\\n│ │ │ └── index.ts\\n│ │ ├── locale\\\\\\n│ │ │ ├── en_US.ts\\n│ │ │ ├── index.tsx\\n│ │ │ └── zh_CN.ts\\n│ │ ├── router\\\\\\n│ │ │ ├── detailRouter.tsx\\n│ │ │ ├── index.tsx\\n│ │ │ ├── mainRouter.tsx\\n│ │ │ ├── type.ts\\n│ │ │ └── useRoute.tsx\\n│ │ ├── store\\\\\\n│ │ │ ├── commonReducer\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── datasourceReducer\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── userReducer\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── workSpaceReducer\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── index.ts\\n│ │ │ ├── rootReducer.ts\\n│ │ │ └── useActions.ts\\n│ │ ├── theme\\\\\\n│ │ │ └── index.tsx\\n│ │ ├── type\\\\\\n│ │ │ ├── JobExecutionLogs.ts\\n│ │ │ ├── JobQualityReport.ts\\n│ │ │ ├── Jobs.ts\\n│ │ │ ├── JobsInstance.ts\\n│ │ │ ├── Notification.ts\\n│ │ │ ├── User.ts\\n│ │ │ ├── config.ts\\n│ │ │ ├── dataSource.ts\\n│ │ │ ├── errorData.ts\\n│ │ │ ├── metadata.ts\\n│ │ │ ├── token.ts\\n│ │ │ ├── warning.ts\\n│ │ │ └── workSpace.ts\\n│ │ ├── utils\\\\\\n│ │ │ ├── shareData\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── base64.ts\\n│ │ │ ├── constants.ts\\n│ │ │ ├── helper.tsx\\n│ │ │ └── index.ts\\n│ │ ├── view\\\\\\n│ │ │ ├── ForgetPassword\\\\\\n│ │ │ │ └── ... 2 files, 0 dirs not shown\\n│ │ │ ├── JobHistory\\\\\\n│ │ │ │ └── ... 1 files, 0 dirs not shown\\n│ │ │ ├── Login\\\\\\n│ │ │ │ └── ... 2 files, 0 dirs not shown\\n│ │ │ ├── Main\\\\\\n│ │ │ │ └── ... 1 files, 8 dirs not shown\\n│ │ │ └── Register\\\\\\n│ │ │ └── ... 2 files, 0 dirs not shown\\n│ │ ├── global.less\\n│ │ ├── index.tsx\\n│ │ └── preset.ts\\n│ ├── typings\\\\\\n│ │ └── global.d.ts\\n│ ├── .editorconfig\\n│ ├── .eslintignore\\n│ ├── .eslintrc.js\\n│ ├── babel.config.js\\n│ ├── build.js\\n│ ├── package.json\\n│ ├── pom.xml\\n│ ├── postcss.config.js\\n│ ├── readme.md\\n│ ├── tsconfig.json\\n│ └── webpack.config.js\\n├── deploy\\\\\\n│ ├── compose\\\\\\n│ │ ├── .env\\n│ │ └── docker-compose.yaml\\n│ ├── docker\\\\\\n│ │ └── Dockerfile\\n│ └── k8s\\\\\\n│ └── datavines.yaml\\n├── scripts\\\\sql\\\\\\n│ └── datavines-mysql.sql\\n├── tools\\\\checkstyle\\\\\\n│ └── checkStyle.xml\\n├── .gitignore\\n├── HEADER\\n├── README.md\\n├── README.zh-CN.md\\n├── mvnw\\n└── pom.xml\\n\"","current_document_structure":"WikiEncrypted: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","catalogue_think_content":"WikiEncrypted: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","recovery_checkpoint":"wiki_generation_completed","last_commit_id":"5334219cbd2ad982b091ed1a83f7b0ce664cfb3f","last_commit_update":"2026-02-03T10:01:39+08:00","gmt_create":"2025-12-25T23:36:54+08:00","gmt_modified":"2026-02-25T21:14:46.772479+08:00","extend_info":"{\"language\":\"zh\",\"active\":true,\"branch\":\"dev\",\"shareStatus\":\"WIKI_HAS_CHANGE\",\"server_error_code\":\"\",\"cosy_version\":\"0.2.25\"}"}} \ No newline at end of file