揭秘云原生混布资源调度器Koordinator (十)ResourceExecutor 执行引擎

核心使命与设计理念

10.1 What - ResourceExecutor 是什么?

ResourceExecutor 是 Koordlet 中的资源操作执行引擎,负责将 QOSManager 的决策转化为具体的 CGroup 操作指令,并确保指令正确执行。

核心职责

  1. 接收执行指令:从 QOSManager 接收资源隔离和限流指令
  2. 管理 CGroup:更新 Pod 对应的 CGroup 配置文件
  3. 批量执行:支持批量和增量更新,提高效率
  4. 错误处理:处理执行失败,提供重试机制
  5. 状态同步:同步执行结果,反馈给 QOSManager
  6. 幂等性:确保重复执行相同指令不会产生副作用

执行层次

yaml 复制代码
┌─────────────────────────────────────────────┐
│      ResourceExecutor 的执行层次            │
├─────────────────────────────────────────────┤
│                                             │
│ L1: 策略层(QOSManager)                   │
│    ├─ CPU 压力 > 90                        │
│    ├─ 决策: 驱逐 3 个 BE Pod               │
│    └─ 调用 ResourceExecutor                │
│                                             │
│ L2: 指令层(ResourceExecutor)              │
│    ├─ 指令 1: 更新 BE Pod 1 的 quota      │
│    ├─ 指令 2: 更新 BE Pod 2 的 quota      │
│    └─ 指令 3: 驱逐 BE Pod 3               │
│                                             │
│ L3: 操作层(CGroup 文件系统)              │
│    ├─ 写入 /sys/fs/cgroup/cpu/.../quota  │
│    ├─ 写入 /sys/fs/cgroup/memory/.../min │
│    └─ 删除 Pod 对应的 CGroup               │
│                                             │
│ L4: 内核层(Linux Kernel)                 │
│    ├─ CFS 调度器应用新 quota               │
│    ├─ 内存管理器执行回收                   │
│    └─ 进程被限流或终止                     │
│                                             │
└─────────────────────────────────────────────┘

10.2 Why - 为什么需要专门的执行引擎?

问题 1:直接修改 CGroup 容易出错

markdown 复制代码
低效的方式(逐个修改):

for each pod in pods_to_update:
    write(pod.cgroup_cpu_quota, new_quota)
    write(pod.cgroup_memory_min, new_min)
    write(pod.cgroup_io_weight, new_weight)

问题:
├─ 每个 Pod 3 次文件写操作 → 频繁系统调用
├─ 写入期间不一致 → 某些参数已更新,某些未更新
├─ 如果中间出错 → Pod 处于不完整的状态
└─ 无法回滚 → 无法恢复到之前的状态

ResourceExecutor 的方案:

1. 批量收集所有指令
2. 验证指令的一致性
3. 原子性执行(全部成功或全部失败)
4. 保存执行历史(便于调试和回滚)

问题 2:CGroup 操作的复杂性和陷阱

yaml 复制代码
CGroup 操作的常见陷阱:

陷阱 1: 内存限制的顺序
├─ 错误: 先设置 memory.min,后设置 memory.max
│       ├─ 如果 min > max,操作会失败
│       └─ 导致设置不成功
│
├─ 正确: 先确保 max >= min
│       └─ 避免顺序导致的失败

陷阱 2: CPU quota 的边界值
├─ quota 范围: 1000 ~ 18446744073709551615 (2^64-1)
├─ 错误: quota=0 或 quota=-1(无限制)不同含义
└─ 需要: 明确区分有限制和无限制的情况

陷阱 3: CGroup v1 和 v2 的差异
├─ v1: cpu/cpuacct 分开
├─ v2: unified 子系统
├─ 需要: 同时支持两个版本
└─ 不能混淆 API

陷阱 4: 权限问题
├─ 普通用户无法修改 CGroup
├─ 需要: root 权限或特殊配置
└─ RuntimeProxy: 在容器创建时注入参数

ResourceExecutor 的设计目标:
└─ 统一处理这些复杂性和陷阱
└─ 向上层提供简单、安全的 API

问题 3:需要支持高效的批量和增量操作

ini 复制代码
场景:200 个 Pod 的节点,每秒更新参数

不优化的方案:
├─ 200 个 Pod × 3 个参数 = 600 次文件操作
├─ 每次操作 1ms → 总耗时 600ms
├─ 频繁的系统调用,CPU 占用高
└─ 可能无法按时完成

优化方案(ResourceExecutor):

1. 增量更新
   ├─ 只更新有变化的 Pod
   ├─ 例:仅 50 个 Pod 的参数变化
   └─ 50 × 3 = 150 次操作

2. 批量操作
   ├─ 合并同一 CGroup 的多个参数更新
   ├─ 例:cpuset 和 cpu.shares 一起更新
   └─ 减少文件操作次数

3. 异步更新
   ├─ 不阻塞 QOSManager 的决策循环
   ├─ 在后台线程执行
   └─ QOSManager 继续做下一轮决策

4. 优先级队列
   ├─ 优先执行关键操作(驱逐、防 OOM)
   ├─ 延迟执行非关键操作(轻微抑制)
   └─ 有限的执行资源,优先处理紧急任务

性能对比:

场景: 200 Pod,50 个需要更新,3 个参数/Pod

不优化:
├─ 更新所有: 600 次 I/O × 1ms = 600ms
└─ 无法按时完成 1s 的决策周期

优化后:
├─ 增量: 150 次 I/O × 1ms = 150ms
├─ 批量: 100 次 I/O × 1ms = 100ms
├─ 异步: 在后台,不阻塞主循环
└─ 总耗时: < 100ms,轻松完成

10.3 How - 执行引擎的实现架构

yaml 复制代码
┌──────────────────────────────────────────────┐
│       ResourceExecutor 工作流程              │
├──────────────────────────────────────────────┤
│                                              │
│ 1. 指令收集(来自 QOSManager)               │
│    ├─ UpdateRequest: 更新 Pod 的资源参数   │
│    ├─ EvictionRequest: 驱逐 Pod            │
│    ├─ ReservationRequest: 资源预留         │
│    └─ 批量收集,避免逐个处理               │
│                                              │
│ 2. 指令验证                                  │
│    ├─ 检查指令的合法性                      │
│    ├─ 检查参数范围                          │
│    ├─ 检查 Pod 是否存在                    │
│    └─ 过滤无效指令                          │
│                                              │
│ 3. 指令去重和优化                            │
│    ├─ 同一 Pod 的多个更新 → 合并            │
│    ├─ 无效指令 → 删除                      │
│    ├─ 优先级排序 → 紧急指令优先             │
│    └─ 增量计算 → 只更新变化的部分           │
│                                              │
│ 4. 执行前检查                                │
│    ├─ 检查 CGroup 是否存在                 │
│    ├─ 检查目标路径的权限                    │
│    ├─ 读取当前值,对比变化                  │
│    └─ 避免不必要的写入                      │
│                                              │
│ 5. 执行操作                                  │
│    ├─ 按优先级执行                          │
│    ├─ 一个 Pod 的多个参数按顺序执行         │
│    ├─ 支持重试(瞬时故障)                  │
│    └─ 记录执行日志                          │
│                                              │
│ 6. 错误处理                                  │
│    ├─ 捕获执行异常                          │
│    ├─ 分类处理(可重试/不可重试)           │
│    ├─ 回滚已执行的操作(可选)              │
│    └─ 记录错误,通知上层                    │
│                                              │
│ 7. 结果反馈                                  │
│    ├─ 记录执行结果                          │
│    ├─ 统计执行速度和成功率                  │
│    ├─ 更新 Pod 的资源状态                  │
│    └─ 通知 QOSManager                      │
│                                              │
└──────────────────────────────────────────────┘

分 - ResourceExecutor 的实现细节

10.4 指令的数据结构和优先级

执行指令的类型

go 复制代码
// ResourceUpdateRequest: 更新资源参数
type ResourceUpdateRequest struct {
    PodUID            string
    ResourceType      string        // "cpu", "memory", "io", "network"
    ParameterName     string        // "quota", "shares", "min", "max"
    ParameterValue    interface{}   // 参数值
    Priority          int           // 0-10, 越小越紧急
    DeadlineNano      int64         // 执行截止时间(纳秒)
    Reason            string        // 执行原因,用于日志
}

// EvictionRequest: 驱逐 Pod
type EvictionRequest struct {
    PodUID            string
    Namespace         string
    PodName           string
    Reason            string        // 驱逐原因
    Priority          int           // 驱逐优先级
    GracePeriodSecond int           // 优雅关闭时间
}

// 优先级定义
const (
    PriorityEmergency  = 0   // 紧急(SLO 违反)
    PriorityHigh       = 3   // 高(CPU 压力 > 90)
    PriorityMedium     = 5   // 中等(CPU 压力 60-90)
    PriorityLow        = 8   // 低(日常调整)
    PriorityBatch      = 10  // 批处理(可延迟)
)

优先级排序规则

ini 复制代码
同一批次内的指令排序:

1. Priority 值(越小越优先)
   ├─ PriorityEmergency (0): 驱逐、防 OOM
   ├─ PriorityHigh (3): CPU 紧急抑制
   ├─ PriorityMedium (5): CPU 正常抑制
   ├─ PriorityLow (8): 日常参数调整
   └─ PriorityBatch (10): 非关键更新

2. 截止时间(越早越优先)
   ├─ 即将超时的指令优先执行
   └─ 避免关键指令被延迟

3. 资源类型(关键资源优先)
   ├─ CPU 驱逐 > 内存驱逐 > 其他
   └─ CPU 是最关键的资源

4. Pod 数量(影响范围大的优先)
   ├─ 影响 100 个 Pod 的操作优先
   ├─ 影响 10 个 Pod 的操作其次
   └─ 影响 1 个 Pod 的操作最后

示例排序:

原始列表:
├─ Request 1: CPU.quota, Priority=5, Deadline=3000ms (中等,3秒)
├─ Request 2: Memory.min, Priority=0, Deadline=5000ms (紧急,5秒)
├─ Request 3: CPU.shares, Priority=8, Deadline=6000ms (低,6秒)
└─ Request 4: CPU.quota, Priority=0, Deadline=2000ms (紧急,2秒)

排序后:
├─ Request 4: Priority=0, Deadline=2000ms ← 紧急且即将超时
├─ Request 2: Priority=0, Deadline=5000ms ← 紧急但时间充足
├─ Request 1: Priority=5, Deadline=3000ms ← 中等
└─ Request 3: Priority=8, Deadline=6000ms ← 低

10.5 批量操作和增量更新

增量计算的实现

ini 复制代码
增量更新的目标:
└─ 只更新有变化的参数
└─ 避免不必要的 CGroup 写操作

算法流程:

步骤 1: 读取当前值
    current_quota = read_from_cgroup(pod_cgroup_path)

步骤 2: 对比新值
    if current_quota == new_quota:
        skip_update()
    else:
        execute_update()

示例:

场景: 200 个 Pod,每秒更新

全量更新(无优化):
├─ 200 个 Pod × 3 个参数 = 600 次写操作
└─ 600ms (每次 1ms)

增量更新(有优化):
├─ 检查当前值 200 × 3 = 600 次读操作(并行,< 100ms)
├─ 发现 150 个 Pod 需要更新
├─ 执行 150 × 3 = 450 次写操作(< 450ms)
└─ 总计: < 550ms(比全量快 50ms)

批量操作的优化:

不优化:
for each pod in pods:
    for each param in params:
        write(cgroup_path, param, value)

优化后:
batch = []
for each pod in pods:
    for each param in params:
        batch.append((cgroup_path, param, value))

execute_batch(batch)  # 一次性执行,减少系统调用

性能提升:
├─ 系统调用从 600 次 → 1 次(减少 99.8%)
├─ 用户态/内核态切换从 1200 次 → 2 次
└─ 总耗时从 600ms → 100ms

生产案例:批量操作的性能提升

ini 复制代码
场景:1024 核节点,500 个 Pod,每秒更新

不使用批量优化:
┌─────────────────────────────────────┐
│ 执行时间分析:                       │
├─────────────────────────────────────┤
│ 读取 Pod 信息: 50ms                 │
│ 生成指令: 20ms                      │
│ 修改 CGroup(500 × 3):            │
│ ├─ 用户态准备: 200ms                │
│ ├─ 系统调用: 1200 × 1ms = 1200ms   │
│ ├─ 内核执行: 300ms                 │
│ └─ 返回用户态: 200ms                │
│ 验证结果: 30ms                      │
│                                     │
│ 总计: 2000ms > 1000ms (超时!)     │
│                                     │
│ 问题:                               │
│ ├─ QOSManager 的 1s 决策周期无法完成│
│ ├─ 执行延迟,导致决策滞后           │
│ └─ 资源隔离不及时                   │
└─────────────────────────────────────┘

使用批量优化:
┌─────────────────────────────────────┐
│ 执行时间分析:                       │
├─────────────────────────────────────┤
│ 读取 Pod 信息: 50ms                 │
│ 生成指令: 20ms                      │
│ 修改 CGroup(批量):                │
│ ├─ 用户态准备: 200ms                │
│ ├─ 系统调用: 1 次 × 1ms = 1ms      │
│ ├─ 内核执行: 300ms                 │
│ └─ 返回用户态: 10ms                 │
│ 验证结果: 30ms                      │
│                                     │
│ 总计: 611ms < 1000ms (满足!)     │
│                                     │
│ 改进:                               │
│ ├─ 执行延迟从 2000ms 降到 611ms    │
│ ├─ 系统调用从 1200 次降到 1 次     │
│ ├─ 缓冲充足,可以执行其他操作      │
│ └─ 资源隔离及时有效                │
└─────────────────────────────────────┘

关键优化点:
├─ 批量 CGroup 操作 → 减少系统调用
├─ 增量更新 → 只更新变化的 Pod
├─ 异步执行 → 不阻塞 QOSManager
└─ 优先级排序 → 关键操作优先

10.6 错误处理和重试机制

错误分类

go 复制代码
CGroup 操作的错误类型:

可重试错误:
├─ EIO (I/O error): 瞬时 I/O 故障
│  └─ 解决: 等待后重试
│
├─ EAGAIN (Resource temporarily unavailable): 资源暂时不可用
│  └─ 解决: 等待后重试
│
├─ EINTR (Interrupted system call): 系统中断
│  └─ 解决: 重试系统调用
│
└─ 超时: 操作超过设定时间
   └─ 解决: 增加超时时间后重试

不可重试错误:
├─ ENOENT (No such file or directory): CGroup 不存在
│  └─ 原因: Pod 已删除或路径错误
│  └─ 处理: 记录日志,跳过
│
├─ EACCES (Permission denied): 权限不足
│  └─ 原因: 进程权限不足
│  └─ 处理: 记录错误,需要提权
│
├─ EINVAL (Invalid argument): 参数无效
│  └─ 原因: 参数超出范围或格式错误
│  └─ 处理: 记录日志,跳过
│
└─ ERANGE (Numerical result out of range): 数值范围外
   └─ 原因: 内存限制值不合理(min > max)
   └─ 处理: 调整参数后重试

重试策略:

func ExecuteWithRetry(request Request) error {
    max_retries := 3
    retry_delay := 100ms
    
    for attempt := 0; attempt < max_retries; attempt++ {
        err := Execute(request)
        
        if err == nil {
            return nil  // 成功
        }
        
        if !IsRetryable(err) {
            return err  // 不可重试,返回错误
        }
        
        if attempt < max_retries - 1 {
            wait(retry_delay)
            retry_delay *= 2  // 指数退避
        }
    }
    
    return errors.New("max retries exceeded")
}

生产案例:处理 CGroup 不存在

ini 复制代码
场景:Pod 在执行操作期间被删除

时间线:

T=10:00:00  QOSManager 检测到 CPU 压力
            ├─ 决策: 更新 Pod A 的 quota
            └─ 发送更新请求到 ResourceExecutor

T=10:00:01  ResourceExecutor 收到请求
            ├─ 验证 Pod A 存在(检查成功)
            └─ 加入执行队列

T=10:00:02  Pod A 被驱逐
            ├─ Kubernetes 删除 Pod
            ├─ CGroup 也被删除
            └─ Pod A 的资源释放

T=10:00:03  ResourceExecutor 开始执行
            ├─ 尝试打开 CGroup 路径
            ├─ 文件不存在 → ENOENT 错误
            └─ 该如何处理?

不使用错误处理:
┌─────────────────────────────────────┐
│ 执行失败,异常抛出                   │
│ ├─ ResourceExecutor crash            │
│ ├─ 之后的所有操作停止                │
│ ├─ 其他 Pod 的参数无法更新           │
│ └─ 整个资源隔离系统停止工作          │
└─────────────────────────────────────┘

使用错误处理:
┌─────────────────────────────────────┐
│ 捕获 ENOENT 错误                     │
│ ├─ 检查:Pod 是否还存在?            │
│ │  └─ 检查 StatesInformer 的缓存     │
│ │  └─ 发现 Pod A 已被删除            │
│ │  └─ 确认是 Pod 删除,不是路径错误  │
│ │                                     │
│ ├─ 处理:略过该 Pod                  │
│ │  └─ 从执行队列中移除 Pod A 的请求  │
│ │  └─ 记录日志: "Pod A 已删除,跳过" │
│ │                                     │
│ └─ 继续执行下一个 Pod(Pod B)        │
│                                     │
│ 结果:                               │
│ ├─ ResourceExecutor 继续工作          │
│ ├─ 其他 Pod 的参数正常更新           │
│ ├─ 系统稳定                          │
│ └─ 仅记录一条日志,无其他影响       │
└─────────────────────────────────────┘

错误分析的流程:

ENOENT 错误
    ↓
检查 Pod 是否在 StatesInformer 中
    ├─ 存在 → 路径错误,重新计算路径
    ├─ 不存在 → Pod 已删除,安全跳过
    └─ 不确定 → 记录日志,跳过
    ↓
继续执行下一个操作

优势:
├─ 自动适应 Pod 的生命周期变化
├─ 不因为 Pod 删除而崩溃
└─ 提高系统鲁棒性

10.7 执行性能优化

并行执行的策略

go 复制代码
CGroup 操作的并行可行性:

可以并行的操作:
├─ 不同 Pod 的操作 → 完全独立
├─ 不同 CGroup 子系统的操作 → 独立
└─ 读操作 → 可以并行读

不能并行的操作:
├─ 同一文件的读-写 → 可能不一致
├─ 内存的 min/max 操作 → 有依赖关系
│  └─ 必须确保 min <= max
└─ 同一 Pod 的多个参数更新 → 需要原子性

并行执行的实现:

type UpdateBatch struct {
    requests []UpdateRequest
    // 按 Pod 分组
    by_pod := group_by(requests, pod_uid)
    // 按资源类型分组
    by_resource := group_by(requests, resource_type)
}

ExecuteParallel(batch) {
    // 步骤 1: 内存操作(有依赖)
    memory_requests := filter(batch, resource="memory")
    for request in memory_requests {
        ExecuteMemoryUpdate(request)  // 串行
    }
    
    // 步骤 2: CPU 操作(独立)
    cpu_requests := filter(batch, resource="cpu")
    
    // 创建 goroutine 池
    workers := 4  // 4 个并行 worker
    work_queue := make(chan UpdateRequest)
    
    // 启动 worker
    for i := 0; i < workers; i++ {
        go Worker(work_queue)
    }
    
    // 分配任务
    for request in cpu_requests {
        work_queue <- request
    }
    
    close(work_queue)
    wait_for_all()
}

性能提升:

场景: 200 个 Pod,4 个 CPU 并行 worker

串行执行:
├─ 内存操作: 50 Pod × 2 params × 1ms = 100ms
├─ CPU 操作: 200 Pod × 2 params × 1ms = 400ms
└─ 总计: 500ms

并行执行(4 workers):
├─ 内存操作: 50 × 2 × 1ms = 100ms(串行)
├─ CPU 操作: 200 × 2 × 1ms / 4 = 100ms(并行)
└─ 总计: 200ms(提升 60%)

生产调优指南

10.8 ResourceExecutor 配置

yaml 复制代码
# ResourceExecutor 配置示例
apiVersion: v1
kind: ConfigMap
metadata:
  name: koordlet-config
  namespace: koordinator-system
data:
  resource-executor-config.yaml: |
    resourceExecutor:
      # 执行线程池
      threadPoolSize: 4              # 并行 worker 数
      queueSize: 1000                # 等待队列大小
      
      # 执行参数
      batchSize: 100                 # 单次批处理大小
      batchInterval: 100ms           # 批处理间隔
      
      # 超时配置
      executionTimeout: 5s           # 单个操作超时
      overallTimeout: 30s            # 整批操作超时
      
      # 重试配置
      maxRetries: 3                  # 最大重试次数
      retryDelay: 100ms              # 初始重试延迟
      maxRetryDelay: 2s              # 最大重试延迟
      
      # 优先级队列
      priorityQueueEnabled: true     # 启用优先级队列
      
      # 增量更新
      incrementalUpdate: true        # 启用增量更新
      changeThreshold: 0             # 变化阈值(0=全部更新)
      
      # 日志和监控
      verboseLogging: false          # 详细日志
      metricsEnabled: true           # 启用监控指标
      slowLogThreshold: 500ms        # 慢操作日志阈值

10.9 常见问题排查

问题 1:CGroup 操作超时

shell 复制代码
诊断:

1. 检查执行延迟
   $ kubectl logs koordlet-xxx | grep "execution timeout"
   
   如果频繁超时:
   └─ 系统 I/O 过载或权限问题

2. 检查系统负载
   $ top
   $ iostat -x 1
   
   如果 I/O wait > 50%:
   └─ 磁盘 I/O 过载

3. 检查 CGroup 文件系统
   $ df /sys/fs/cgroup
   $ ls -la /sys/fs/cgroup/cpu/...
   
   如果文件操作慢:
   └─ CGroup 文件系统问题

解决方案:
├─ 增加 executionTimeout: 5s → 10s
├─ 减少 batchSize: 100 → 50
├─ 增加 batchInterval: 100ms → 200ms
└─ 并行 worker 数不要过多

问题 2:内存限制设置失败

matlab 复制代码
诊断:

1. 检查错误日志
   $ kubectl logs koordlet-xxx | grep "EINVAL\|ERANGE"
   
   如果显示 memory.min > memory.max:
   └─ 参数设置顺序错误

2. 验证当前 CGroup 配置
   $ cat /sys/fs/cgroup/memory/kubepods/pod-uid/memory.min
   $ cat /sys/fs/cgroup/memory/kubepods/pod-uid/memory.max
   
   如果 min > max:
   └─ 之前的操作部分失败

解决方案:
├─ 确保操作顺序: min <= soft_limit <= high <= max
├─ 先调大 max,再调小 min
├─ 使用事务性操作确保一致性

问题 3:Pod 删除期间的操作失败

shell 复制代码
诊断:

1. 检查 ENOENT 错误频率
   $ promql: koordlet_resource_executor_errors{error="ENOENT"}
   
   如果频率高:
   └─ Pod 删除频率高,正常现象

2. 检查日志中的错误处理
   $ kubectl logs koordlet-xxx | grep "ENOENT"
   
   如果只有日志,无 crash:
   └─ 错误处理正确

解决方案:
├─ 确保 ENOENT 错误被正确处理
├─ 不应该导致 ResourceExecutor crash
└─ 监控错误率,异常告警

10.10 监控指标

promql 复制代码
# ResourceExecutor 关键指标

# 执行延迟
koordlet_resource_executor_latency_milliseconds{operation="update"}
koordlet_resource_executor_latency_milliseconds{operation="evict"}

# 执行成功率
koordlet_resource_executor_success_total
koordlet_resource_executor_errors_total{error_type="ENOENT"}

# 队列深度
koordlet_resource_executor_queue_depth

# 批量操作的大小
koordlet_resource_executor_batch_size

# 并行 worker 的负载
koordlet_resource_executor_worker_busy_ratio

# 重试次数
koordlet_resource_executor_retries_total

# 慢操作日志
koordlet_resource_executor_slow_operations_total

总结 - 章节要点汇总

10.11 关键概念速查

概念 含义 重要性
增量更新 只更新变化的参数
批量操作 合并多个操作,减少系统调用
优先级队列 关键操作优先执行
并行执行 多线程并行处理独立操作
错误重试 可重试错误自动重试

10.12 最佳实践

  • 启用增量更新,避免不必要的 CGroup 操作
  • 使用优先级队列,关键操作优先执行
  • 正确处理 ENOENT 错误,不应该导致 crash
  • 并行执行不相关的操作,提高吞吐量
  • 监控执行延迟和成功率,及时发现问题
相关推荐
一颗小青松2 小时前
uniapp vue3中app端使用腾讯云点播上传
uni-app·云计算·腾讯云
HelloWorld__K2 小时前
整合阿里云短信服务
数据库·阿里云·云计算
翼龙云_cloud3 小时前
亚马逊云渠道商:如何解决AWS EC2搭建的网站无法访问?
运维·云计算·aws
com_4sapi3 小时前
星链引擎4SAPICOM:全球API服务平台优选,助力企业高效连接智能生态
大数据·人工智能·云计算
2501_939909053 小时前
基于Docker与Jenkins实现RuoYi-Vue项目的CICD持续集成部署
云计算
骥龙3 小时前
第四篇:融合篇——架构的涌现效应:1+1>2
运维·架构·云计算
翼龙云_cloud4 小时前
阿里云云渠道商:GPU 服务器安全组配置指南 3 步解决端口开放问题
运维·服务器·安全·阿里云·云计算
helloliyh5 小时前
腾讯云获取secretId和secretKey并开通人脸识别服务
云计算·腾讯云
2401_865854885 小时前
腾讯云音视频和其他平台对比有哪些优势
云计算·音视频·腾讯云